From e63516d5ea7ee90863c1c8dd267e337e2f043fda Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 11 Sep 2019 19:11:19 +0800 Subject: [PATCH 01/31] implement of MISRA-C compliant TVM runtime; --- src/runtime/crt/c_api_common.h | 26 ++ src/runtime/crt/graph_runtime.c | 361 +++++++++++++++++++++++ src/runtime/crt/graph_runtime.h | 507 ++++++++++++++++++++++++++++++++ src/runtime/crt/load_json.c | 47 +++ src/runtime/crt/load_json.h | 376 +++++++++++++++++++++++ src/runtime/crt/module.h | 55 ++++ src/runtime/crt/ndarray.c | 78 +++++ src/runtime/crt/ndarray.h | 113 +++++++ 8 files changed, 1563 insertions(+) create mode 100644 src/runtime/crt/c_api_common.h create mode 100644 src/runtime/crt/graph_runtime.c create mode 100644 src/runtime/crt/graph_runtime.h create mode 100644 src/runtime/crt/load_json.c create mode 100644 src/runtime/crt/load_json.h create mode 100644 src/runtime/crt/module.h create mode 100644 src/runtime/crt/ndarray.c create mode 100644 src/runtime/crt/ndarray.h diff --git a/src/runtime/crt/c_api_common.h b/src/runtime/crt/c_api_common.h new file mode 100644 index 000000000000..b4d3d9489539 --- /dev/null +++ b/src/runtime/crt/c_api_common.h @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \file c_api_common.h + * \brief Common fields of all C APIs + */ + +#define API_BEGIN() int status; do { status = TVM_STATUS_SUCCESS; } while(false) +#define API_END() return status diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c new file mode 100644 index 000000000000..709acc1ed2e3 --- /dev/null +++ b/src/runtime/crt/graph_runtime.c @@ -0,0 +1,361 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * Copyright (c) 2017 by Contributors + * \file graph_runtime.c + */ +#include "graph_runtime.h" +#include "c_api_common.h" +#include "load_param.h" + +/*! + * \brief Get the input index given the name of input. + * \param name The name of the input. + * \return The index of input. + */ +int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { + uint32_t i; + int32_t rv = -1; + for (i = 0; i< runtime->input_nodes_count; ++i) { + uint32_t nid = runtime->input_nodes[i]; + if (!strcmp(runtime->nodes[nid].name, name)) { + rv = i; + break; + } + } + if (rv < 0) { + LOGE("cannot find \"%s\" among input", name); + } + return rv; +} + +/*! + * \brief set index-th input to the graph. + * \param index The input index. + * \param data_in The input data. + */ +void GraphRuntime_SetInput(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in) { + uint32_t index = runtime->GetInputIndex(runtime, name); + if (index >= runtime->input_nodes_count) { + LOGE("given index is greater than num of input nodes."); + } + uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[index], 0); + runtime->data_entry[eid].dl_tensor = *data_in; +} + +int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param_blob, const uint32_t param_size) { + API_BEGIN(); + const char * bptr = param_blob; + uint64_t header, reserved; + header = ((uint64_t*)bptr)[0]; + bptr += sizeof(header); + if (header != kTVMNDArrayListMagic) { + LOGE("Invalid parameters file format"); + } + reserved = ((uint64_t*)bptr)[0]; + bptr += sizeof(reserved); + + // read names + char names[GRAPH_RUNTIME_MAX_NODES][80]; + memset(names, 0, sizeof(names)); + uint64_t names_count; + int idx; + names_count = ((uint64_t*)bptr)[0]; + bptr += sizeof(names_count); + for (idx = 0; idx < names_count; idx++) { + uint64_t name_length; + name_length = ((uint64_t*)bptr)[0]; + bptr += sizeof(name_length); + if (name_length >= 80){ + LOGE("Error: function name longer than expected."); + } + memcpy(names[idx], bptr, name_length); + bptr += name_length; + } + + // read sizes + uint64_t sz; + sz = ((uint64_t*)bptr)[0]; + bptr += sizeof(sz); + uint32_t size = sz; + if (size != names_count) { + LOGE("Invalid parameters file format"); + status = TVM_STATUS_FAILURE; + } + + for (idx = 0; idx < size; idx++) { + int32_t in_idx = runtime->GetInputIndex(runtime, names[idx]); + if (!(in_idx >= 0)) { + LOGE("Found param for non-existent input: %s", names[idx]); + status = TVM_STATUS_FAILURE; + } + uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[in_idx], 0); + if (!(eid < runtime->data_entry_count)) { + LOGE("`entry_id`=%d is greater than expected(%d).", eid, runtime->data_entry_count); + status = TVM_STATUS_FAILURE; + } + + NDArray_Load(&(runtime->data_entry[eid]), &bptr); +#if TVM_CRT_DEBUG + char shape_desc[20]; + memset(shape_desc, 0, sizeof(shape_desc)); + NDArray * entry = &(runtime->data_entry[eid]); + Shape_Print(shape_desc, entry->dl_tensor.shape, entry->dl_tensor.ndim); + LOGI("param %s loaded, in_idx=%d, eid=%d, ndim=%d, shape=%s, data[0]=%f", + names[idx], in_idx, eid, entry->dl_tensor.ndim, shape_desc, + ((float*)entry->dl_tensor.data)[0]); +#endif // TVM_CRT_DEBUG + } + + API_END(); +} + +/*! + * \brief Run all the operations one by one. + */ +void GraphRuntime_Run(GraphRuntime * runtime) { + // setup the array and requirements. + uint32_t idx; + for (idx = 0; idx < runtime->op_execs_count; ++idx) { + if (runtime->op_execs[idx].fexec) { +#if TVM_CRT_DEBUG + LOGI("calling %s (%d)", runtime->op_execs[idx].name, idx); +#endif // TVM_CRT_DEBUG + runtime->op_execs[idx].Call(&(runtime->op_execs[idx])); + } + } +} + +int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * out) { + int status = TVM_STATUS_SUCCESS; + uint32_t nid = runtime->outputs[idx].node_id; + uint32_t index = runtime->outputs[idx].index; + uint32_t eid = runtime->GetEntryId(runtime, nid, index); + *out = runtime->data_entry[eid].dl_tensor; + return status; +} + +void GraphRuntime_SetupStorage(GraphRuntime * runtime) { + uint32_t idx, dim; + + // Grab saved optimization plan from graph. + TVMType vtype[GRAPH_RUNTIME_MAX_NODES]; + GraphRuntimeGraphAttr * attrs = &(runtime->attrs); + for (idx = 0; idx < attrs->dltype_count; idx++) { + vtype[idx] = String2TVMType(attrs->dltype[idx]); + } + + // Size and device type of each storage pool entry. + PoolEntry pool_entry[GRAPH_RUNTIME_MAX_NODES]; + memset(pool_entry, 0, sizeof(pool_entry)); + uint32_t pool_entry_count = 0; + // Find the maximum space size. + for (idx = 0; idx < attrs->shape_count; idx++) { + int storage_id = attrs->storage_id[idx]; + // Use the fallback device if no device index is available. + int device_type = runtime->ctxs[0].device_type; + uint32_t size = 1; + for (dim = 0; dim < TVM_CRT_MAX_NDIM; dim++) { + if (attrs->shape[idx][dim] != 0){ + size *= attrs->shape[idx][dim]; + } + } + TVMType t = vtype[idx]; + uint32_t bits = t.bits * t.lanes; + size_t bytes = ((bits + 7U) / 8U) * size; + + uint32_t sid = storage_id; + if (sid >= pool_entry_count) { + pool_entry_count = sid + 1; + } + pool_entry[sid].size = MAX(pool_entry[sid].size, bytes); + pool_entry[sid].device_type = device_type; + } + + // Allocate the space. + for (idx = 0; idx < pool_entry_count; idx++) { + PoolEntry pit = pool_entry[idx]; + int64_t shape[TVM_CRT_MAX_NDIM] = {0,}; + TVMContext ctx = runtime->ctxs[0]; + DLDataType dtype = {kDLFloat, 32, 1}; + shape[0] = (pit.size + 3) / 4; + uint32_t ndim = Shape_CountNonZero(shape); + runtime->storage_pool[runtime->storage_pool_count] = NDArray_Empty(ndim, shape, dtype, ctx); + if (runtime->storage_pool[runtime->storage_pool_count].dl_tensor.data == 0) { + LOGE("fail to create storage_pool with idx=%d", idx); + } + runtime->storage_pool_count++; + } + + // Assign the pooled entries. A unified memory pool is used to simplifiy + // memory assignment for each node entry. The allocated memory on each device + // is mapped to this pool. + runtime->data_entry_count = runtime->node_row_ptr[runtime->node_row_ptr_count - 1]; + for (idx = 0; idx < runtime->data_entry_count; ++idx) { + int storage_id = attrs->storage_id[idx]; + /* CHECK_LT(static_cast(storage_id), storage_pool_.size()); */ + runtime->data_entry[idx] = + NDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], vtype[idx]); + if (runtime->data_entry[idx].dl_tensor.data == 0) { + LOGE("fail to create for node with idx=%d, storage_id=%d", idx, storage_id); + } + } +} + +int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { + API_BEGIN(); + uint32_t nid, idx; + runtime->op_execs_count = runtime->nodes_count; + for (nid = 0; nid < runtime->nodes_count; nid++) { + const GraphRuntimeNode * inode = runtime->nodes + nid; + if (strcmp(inode->op_type, "null")) { + DLTensorPtr args[GRAPH_RUNTIME_MAX_NODES]; + uint32_t args_count = 0; + for (idx = 0; idx < inode->inputs_count; idx++) { + const NodeEntry * entry = inode->inputs + idx; + uint32_t eid = runtime->GetEntryId(runtime, entry->node_id, entry->index); + args[idx] = &(runtime->data_entry[eid].dl_tensor); + args_count ++; + } + for (idx = 0; idx < inode->param.num_outputs; idx++) { + uint32_t eid = runtime->GetEntryId(runtime, nid, idx); + args[args_count] = &(runtime->data_entry[eid].dl_tensor); + args_count ++; + } + if (strcmp(inode->op_type, "tvm_op")) { + LOGE("Can only take tvm_op as op"); status = TVM_STATUS_FAILURE; + break; + } + if (args_count >= TVM_CRT_MAX_ARGS) { + LOGE("too many arguments: expected less than %d args, but got %d.", TVM_CRT_MAX_ARGS, args_count); + status = TVM_STATUS_FAILURE; + break; + } +#if TVM_CRT_DEBUG + LOGI("creating tvm_op: %s with node_id=%d", inode->param.func_name, nid); +#endif // TVM_CRT_DEBUG + PackedFunc pf; + runtime->CreateTVMOp(runtime, &(inode->param), args, args_count, inode->inputs_count, &pf); + runtime->op_execs[nid] = pf; +#if TVM_CRT_DEBUG + /* (runtime->op_execs[1].args.values[0].v_handle)->ndim = 3; */ + LOGI("DEBUG: (runtime->op_execs[1].args.values[0].v_handle)->ndim=%d", + (runtime->op_execs[1].args.values[0].v_handle)->ndim); + LOGI("DEBUG: (runtime->op_execs[%d].args.values[0].v_handle)->ndim=%d", + nid, (runtime->op_execs[nid].args.values[0].v_handle)->ndim); +#endif // TVM_CRT_DEBUG + } + } + API_END(); +} + +typedef struct opargs_t { + DLTensor args[TVM_CRT_MAX_ARGS]; + uint32_t args_count; + TVMValue arg_values[TVM_CRT_MAX_ARGS]; + uint32_t arg_values_count; + uint32_t arg_tcodes[TVM_CRT_MAX_ARGS]; + uint32_t arg_tcodes_count; + int64_t shape_data[TVM_CRT_MAX_ARGS]; + uint32_t shape_data_count; +} OpArgs; + +int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * param, + DLTensorPtr * args, const uint32_t args_count, + uint32_t num_inputs, PackedFunc * pf) { + uint32_t idx; + OpArgs arg_ptr; + memset(&arg_ptr, 0, sizeof(OpArgs)); + for (idx = 0; idx < args_count; idx++) { + /* arg_ptr.args[idx] = args[idx]; */ + } + arg_ptr.args_count = args_count; + if (param->flatten_data) { + arg_ptr.shape_data_count = arg_ptr.args_count; + } + for (idx = 0; idx < arg_ptr.args_count; ++idx) { + TVMValue v; + memset(&v, 0, sizeof(v)); + DLTensor * t = &(arg_ptr.args[idx]); + /* v.v_handle = &((*args)[idx]); */ + v.v_handle = args[idx]; + arg_ptr.arg_values[idx] = v; + arg_ptr.arg_values_count ++; + arg_ptr.arg_tcodes[idx] = kArrayHandle; + arg_ptr.arg_tcodes_count ++; + if (param->flatten_data) { + arg_ptr.shape_data[idx] = Shape_Accumulate(t->shape); + t->ndim = 1; + t->shape[0] = arg_ptr.shape_data[idx]; + } + } + if (!strcmp(param->func_name, "__nop") || !strcmp(param->func_name, "__copy")) { + LOGE("%s function is not yet supported.", param->func_name); + } + + runtime->module.GetFunction(param->func_name, pf); + TVMArgs targs = TVMArgs_Create(arg_ptr.arg_values, arg_ptr.arg_tcodes, arg_ptr.arg_values_count); +#if TVM_CRT_DEBUG + LOGI("set args for %s function: dims=%d,%d", param->func_name, + (targs.values[0].v_handle)->ndim, (targs.values[1].v_handle)->ndim); +#endif // TVM_CRT_DEBUG + pf->SetArgs(pf, &targs); + + return TVM_STATUS_SUCCESS; +} + +/*! + * \brief Initialize the graph executor with graph and context. + * \param graph_json The execution graph. + * \param module The module containing the compiled functions for the host + * processor. + * \param ctxs The context of the host and devices where graph nodes will be + * executed on. + */ +void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, + const Module * module, const TVMContext * ctxs) { + JSONReader reader = JSONReader_Create(graph_json); + runtime->Load(runtime, &reader); + runtime->ctxs[0] = ctxs[0]; + runtime->SetupStorage(runtime); + PackedFunc_SetupExecs(); + runtime->SetupOpExecs(runtime); +} + +int32_t TVMGraphRuntimeCreate(GraphRuntime * runtime, const char * sym_json, + const Module * m, const TVMContext * ctxs) { + // GraphRuntime runtime; // = (GraphRuntime*)malloc(sizeof(GraphRuntime)); + memset(runtime, 0, sizeof(GraphRuntime)); + runtime->GetEntryId = GraphRuntime_GetEntryId; + runtime->GetInputIndex = GraphRuntime_GetInputIndex; + runtime->Init = GraphRuntime_Init; + runtime->Load = GraphRuntime_Load; + runtime->SetInput = GraphRuntime_SetInput; + runtime->LoadParams = GraphRuntime_LoadParams; + runtime->Run = GraphRuntime_Run; + runtime->GetOutput = GraphRuntime_GetOutput; + runtime->SetupStorage = GraphRuntime_SetupStorage; + runtime->SetupOpExecs = GraphRuntime_SetupOpExecs; + runtime->CreateTVMOp = GraphRuntime_CreateTVMOp; + runtime->module.GetFunction = Module_GetFunction; + // init + runtime->Init(runtime, sym_json, m, ctxs); + return TVM_STATUS_SUCCESS; // ModuleCreate(runtime); +} diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h new file mode 100644 index 000000000000..97e65cd7b59b --- /dev/null +++ b/src/runtime/crt/graph_runtime.h @@ -0,0 +1,507 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * Copyright (c) 2017 by Contributors + * + * \brief Tiny graph runtime that can run graph containing only tvm PackedFunc. + * \file graph_runtime.h + */ +#ifndef TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ +#define TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ + +#include +#include "ndarray.h" +#include "packed_func.h" +#include "module.h" +#include "io.h" +#include "load_json.h" + +/*! \brief macro to do C API call */ +#define TVM_CCALL(func) \ + { \ + int ret = (func); \ + CHECK_EQ(ret, 0) \ + << TVMGetLastError(); \ + } + +/*! \brief operator attributes about tvm op */ +typedef struct tvm_op_param_t { + char func_name[120]; + uint32_t num_inputs; + uint32_t num_outputs; + uint32_t flatten_data; +} TVMOpParam; + +// Memory pool entry. +typedef struct graph_runtime_pool_entry_t { + size_t size; + int device_type; +} PoolEntry; + +// Node entry +typedef struct graph_runtime_node_entry_t { + uint32_t node_id; + uint32_t index; + uint32_t version; + // JSON Loader + void (*Load)(JSONReader *reader); +} NodeEntry; + +static inline int NodeEntry_Load(NodeEntry * entry, JSONReader * reader) { + int status = TVM_STATUS_SUCCESS; + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("invalid json format: failed to parse `node_id`"); } + reader->ReadUnsignedInteger(reader, &(entry->node_id)); + if (!(reader->NextArrayItem(reader))) { LOGE("invalid json format: failed to parse `index`"); } + reader->ReadUnsignedInteger(reader, &(entry->index)); + if (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(entry->version)); + if (reader->NextArrayItem(reader)) { LOGE("invalid json format: failed to parse `version`"); } + } else { + entry->version = 0; + } + return status; +} + +// Node +typedef struct graph_runtime_node_t { + // operator type in string + char op_type[16]; + // name of the op + char name[120]; + // parameters + TVMOpParam param; + // inputs + NodeEntry inputs[GRAPH_RUNTIME_NODE_MAX_INPUTS]; + size_t inputs_count; + // control deps + uint32_t control_deps[200]; + // JSON Loader + void (*LoadAttrs)(struct graph_runtime_node_t * node, JSONReader *reader, TVMOpParam* param); + // JSON Loader + int (*Load)(struct graph_runtime_node_t * node, JSONReader *reader); +} GraphRuntimeNode; + +static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, TVMOpParam* param) { + int bitmask = 0; + char key[20], value[120]; + memset(param, 0, sizeof(TVMOpParam)); + memset(key, 0, sizeof(key)); + memset(value, 0, sizeof(value)); + reader->BeginObject(reader); + while (reader->NextObjectItem(reader, key)) { + reader->ReadString(reader, value); + if (!strcmp(key, "func_name")) { + /* param->func_name = value; */ + strcpy(param->func_name, value); + bitmask |= 1; + } else if (!strcmp(key, "num_inputs")) { + param->num_inputs = strtoul(value, nullptr, 10); + bitmask |= 2; + } else if (!strcmp(key, "num_outputs")) { + param->num_outputs = strtoul(value, nullptr, 10); + bitmask |= 4; + } else if (!strcmp(key, "flatten_data")) { + param->flatten_data = strtoul(value, nullptr, 10); + bitmask |= 8; + } else { + LOGE("do not support key %s", key); + } + } + if (bitmask != (1|2|4|8)) { LOGE("invalid format"); } +} + +static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *reader) { + int status = TVM_STATUS_SUCCESS; + reader->BeginObject(reader); + int bitmask = 0; + char key[20]; + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "op")) { + reader->ReadString(reader, node->op_type); + bitmask |= 1; + } else if (!strcmp(key, "name")) { + reader->ReadString(reader, node->name); + bitmask |= 2; + } else if (!strcmp(key, "inputs")) { + size_t count = node->inputs_count; + if (count >= GRAPH_RUNTIME_NODE_MAX_INPUTS) { + LOGE("The number of inputs in graph runtime node is greater than expected."); + status = TVM_STATUS_FAILURE; + break; + } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + NodeEntry * inputs = node->inputs + count; + reader->BeginArray(reader); + if (!reader->NextArrayItem(reader)) { + LOGE("invalid json format"); + status = TVM_STATUS_FAILURE; + break; + } + reader->ReadUnsignedInteger(reader, &(inputs->node_id)); + if (!reader->NextArrayItem(reader)) { + LOGE("invalid json format"); + status = TVM_STATUS_FAILURE; + break; + } + reader->ReadUnsignedInteger(reader, &(inputs->index)); + if (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(inputs->version)); + if (reader->NextArrayItem(reader)) { + LOGE("invalid json format"); + status = TVM_STATUS_FAILURE; + break; + } + } else { + inputs->version = 0; + } + count++; + } + node->inputs_count = count; + bitmask |= 4; + } else if (!strcmp(key, "attr") || !strcmp(key, "attrs")) { + TVMOpParam param; + + GraphRuntimeNode_LoadAttrs(node, reader, ¶m); + memcpy(&node->param, ¶m, sizeof(param)); + } else if (!strcmp(key, "control_deps")) { + LOGE("do not support key %s", key); + status = TVM_STATUS_FAILURE; + } else { + LOGE("do not support key %s", key); + status = TVM_STATUS_FAILURE; + } + if (status != TVM_STATUS_SUCCESS) { break; } + } + if (bitmask != (1|2|4)) { LOGE("invalid format"); } + return status; +} + +static inline GraphRuntimeNode GraphRuntimeNodeCreate() { + GraphRuntimeNode node; + memset(&node, 0, sizeof(GraphRuntimeNode)); + node.LoadAttrs = GraphRuntimeNode_LoadAttrs; + node.Load = GraphRuntimeNode_Load; + return node; +} + +// Graph attribute +typedef struct graph_runtime_graph_attr_t { + uint32_t storage_num_not_alloctaed; // {0}; + uint32_t storage_id[GRAPH_RUNTIME_MAX_NODES]; + uint32_t device_index[GRAPH_RUNTIME_MAX_NODES]; + char dltype[GRAPH_RUNTIME_MAX_NODES][10]; // "int8", "int16", "float32" + uint32_t dltype_count; + int64_t shape[GRAPH_RUNTIME_MAX_NODES][TVM_CRT_MAX_NDIM]; + uint32_t shape_count; +} GraphRuntimeGraphAttr; + +static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONReader *reader) { + int status = TVM_STATUS_SUCCESS; + int bitmask = 0; + char key[16], type[16]; + uint32_t storage_id_count = 0; + uint32_t dltype_count = 0; + uint32_t shape_count = 0; + uint32_t device_index_count = 0; + reader->BeginObject(reader); + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "dltype")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_str")) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadString(reader, attr->dltype[dltype_count]); + dltype_count ++; + } + attr->dltype_count = dltype_count;; + if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + bitmask |= 1; + } else if (!strcmp(key, "storage_id")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_int")) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(attr->storage_id[storage_id_count])); + storage_id_count++; + } + if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + bitmask |= 2; + } else if (!strcmp(key, "shape")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_shape")) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->BeginArray(reader); + reader->ReadInteger(reader, &(attr->shape[shape_count][0])); + if (reader->NextArrayItem(reader)) { + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][1])); + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][2])); + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][3])); + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][4])); + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][5])); + reader->NextArrayItem(reader); + } + } + } + } + } + } + shape_count ++; + } + attr->shape_count = shape_count; + if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + bitmask |= 4; + } else if (!strcmp(key, "device_index")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_int")) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(attr->device_index[device_index_count])); + device_index_count ++; + } + if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + } else { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + reader->ReadString(reader, type); + if (!strcmp(type, "list_int")) { + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + // std::vector temp; + uint32_t temp[GRAPH_RUNTIME_MAX_NODES]; + uint32_t temp_count = 0; + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(temp[temp_count])); + temp_count ++; + } + } else if (!strcmp(type, "size_t")) { + if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + uint32_t temp; + reader->ReadUnsignedInteger(reader, &temp); + } else { + LOGE("cannot skip graph attr %s", key); + } + if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + } + } + if (bitmask != (1|2|4)) { LOGE("invalid format"); } + return status; +} + + +typedef DLTensor* DLTensorPtr; + +/*! + * \brief Tiny graph runtime. + * + * This runtime can be acccesibly in various language via + * TVM runtime PackedFunc API. + */ +/* class GraphRuntime : public ModuleNode { */ +typedef struct graph_runtime_t { + void (*Run)(struct graph_runtime_t * runtime); + + /*! + * \brief Initialize the graph executor with graph and context. + * \param graph_json The execution graph. + * \param module The module containing the compiled functions for the host + * processor. + * \param ctxs The context of the host and devices where graph nodes will be + * executed on. + */ + void (*Init)(struct graph_runtime_t * runtime, + const char * graph_json, + const Module * module, + const TVMContext * ctxs); + + /*! + * \brief Get the input index given the name of input. + * \param name The name of the input. + * \return The index of input. + */ + int (*GetInputIndex)(struct graph_runtime_t * runtime, const char * name); + + /*! + * \brief set index-th input to the graph. + * \param index The input index. + * \param data_in The input data. + */ + void (*SetInput)(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in); + /*! + * \brief Return NDArray for given output index. + * \param index The output index. + * + * \return NDArray corresponding to given output node index. + */ + int (*GetOutput)(struct graph_runtime_t * runtime, const int32_t index, DLTensor * out); + /*! + * \brief Load parameters from parameter blob. + * \param param_blob A binary blob of parameter. + */ + int (*LoadParams)(struct graph_runtime_t * runtime, const char * param_blob, const uint32_t param_size); + + // The graph attribute fields. + int (*Load)(struct graph_runtime_t * runtime, JSONReader *reader); + /*! \brief Setup the temporal storage */ + void (*SetupStorage)(struct graph_runtime_t * runtime); + /*! \brief Setup the executors. */ + int (*SetupOpExecs)(struct graph_runtime_t * runtime); + + /*! + * \brief Create an execution function given input. + * \param attrs The node attributes. + * \param args The arguments to the functor, including inputs and outputs. + * \param num_inputs Number of inputs. + * \return The created executor. + */ + int32_t (*CreateTVMOp)(struct graph_runtime_t * runtime, const TVMOpParam * attrs, + DLTensorPtr * args, const uint32_t args_count, + uint32_t num_inputs, PackedFunc * pf); + + // Get node entry index. + uint32_t (*GetEntryId)(struct graph_runtime_t * runtime, uint32_t nid, uint32_t index); + + // /*! \brief The graph nodes. */ + /* GraphRuntimeNode nodes_[GRAPH_RUNTIME_MAX_NODES]; */ + GraphRuntimeNode nodes[GRAPH_RUNTIME_MAX_NODES]; + uint32_t nodes_count; + /*! \brief The argument nodes. */ + uint32_t input_nodes[GRAPH_RUNTIME_MAX_INPUT_NODES]; + uint32_t input_nodes_count; + /*! \brief Used for quick entry indexing. */ + uint32_t node_row_ptr[GRAPH_RUNTIME_MAX_NODE_ROW_PTR]; + uint32_t node_row_ptr_count; + /*! \brief Output entries. */ + NodeEntry outputs[GRAPH_RUNTIME_MAX_OUTPUTS]; + uint32_t outputs_count; + /*! \brief Additional graph attributes. */ + GraphRuntimeGraphAttr attrs; + /*! \brief The code module that contains both host and device code. */ + Module module; + /*! \brief Execution context of all devices including the host. */ + TVMContext ctxs[GRAPH_RUNTIME_MAX_CONTEXTS]; + uint32_t ctxs_count; + /*! \brief Common storage pool for all devices. */ + NDArray storage_pool[GRAPH_RUNTIME_MAX_NODES]; + uint32_t storage_pool_count; + /*! \brief Data entry of each node. */ + NDArray data_entry[GRAPH_RUNTIME_MAX_NODES]; + uint32_t data_entry_count; + /*! \brief Operator on each node. */ + PackedFunc op_execs[GRAPH_RUNTIME_MAX_NODES]; + uint32_t op_execs_count; +} GraphRuntime; + +static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) { + int status = TVM_STATUS_SUCCESS; + reader->BeginObject(reader); + int bitmask = 0; + /* String key = StringCreate(); */ + char key[20]; + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "nodes")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + GraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; + status = GraphRuntimeNode_Load(node, reader); + if (status != TVM_STATUS_SUCCESS) { + LOGE("Fail to load an element in `nodes` field in graph runtime node."); + break; +#if TVM_CRT_DEBUG + } else { + LOGI("layer %u: `%s` loaded.", runtime->nodes_count, node->name); +#endif // TVM_CRT_DEBUG + } + runtime->nodes_count ++; /* seq push */ + } + bitmask |= 1; + } else if (!strcmp(key, "arg_nodes")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + uint32_t * node = runtime->input_nodes + runtime->input_nodes_count; + reader->ReadUnsignedInteger(reader, node); + runtime->input_nodes_count ++; + } + bitmask |= 2; + } else if (!strcmp(key, "node_row_ptr")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + uint32_t count = runtime->node_row_ptr_count; + uint32_t * node = runtime->node_row_ptr + count; + reader->ReadUnsignedInteger(reader, node); + runtime->node_row_ptr_count ++; + } + bitmask |= 4; + } else if (!strcmp(key, "heads")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + NodeEntry * entry = runtime->outputs + runtime->outputs_count; + status = NodeEntry_Load(entry, reader); + if (status != TVM_STATUS_SUCCESS) { + LOGE("Fail to load an element in `heads` field in graph runtime node."); + break; + } + runtime->outputs_count ++; /* seq push */ + } + bitmask |= 8; + } else if (!strcmp(key, "attrs")) { + status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); + if (status != TVM_STATUS_SUCCESS) { + LOGE("Fail to load an element in `heads` field in graph runtime node."); + break; + } + bitmask |= 16; + } else if (!strcmp(key, "metadata")) { + break; + } else { + LOGE("key %s is not supported", key); + status = TVM_STATUS_FAILURE; + } + if (status != TVM_STATUS_SUCCESS) { break; } + } + if (!(bitmask == (1|2|4|8|16))) { LOGE("invalid format"); } + return status; +} + +static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, uint32_t nid, uint32_t index) { + return runtime->node_row_ptr[nid] + index; +} + +int32_t TVMGraphRuntimeCreate(GraphRuntime * runtime, const char * sym_json, const Module * m, const TVMContext * ctxs); + +#endif // TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c new file mode 100644 index 000000000000..a3dee0943780 --- /dev/null +++ b/src/runtime/crt/load_json.c @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * Copyright (c) 2016 by Contributors + * \file saveload_json.cc + * \brief Save and load graph to/from JSON file. + */ +#include "load_json.h" + +// the node entry structure in serialized format +typedef struct _JSONNodeEntry { + uint32_t node_id; + uint32_t index; + uint32_t version; + void (*Load)(struct _JSONNodeEntry * entry, JSONReader *reader); +} JSONNodeEntry; + +void JSONNodeEntryLoad(JSONNodeEntry * entry, JSONReader *reader) { + reader->BeginArray(reader); + if (reader->NextArrayItem(reader)) { Printf("invalid json format"); } + reader->ReadUnsignedInteger(reader, &(entry->node_id)); + if (reader->NextArrayItem(reader)) { Printf("invalid json format"); } + reader->ReadUnsignedInteger(reader, &(entry->index)); + if (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(entry->version)); + if (!reader->NextArrayItem(reader)) { Printf("invalid json format"); } + } else { + entry->version = 0; + } +} diff --git a/src/runtime/crt/load_json.h b/src/runtime/crt/load_json.h new file mode 100644 index 000000000000..40a9ceba5e19 --- /dev/null +++ b/src/runtime/crt/load_json.h @@ -0,0 +1,376 @@ +/*! + * Copyright (c) 2015 by Contributors + * \file json.h + * \brief Lightweight JSON Reader that read save into C++ data structs. + * This includes STL composites and structures. + */ +#ifndef LOAD_JSON_H_ +#define LOAD_JSON_H_ + +#include "common.h" + +enum { + JSON_READ_TYPE_U8 = 1, + JSON_READ_TYPE_S8 = 2, + JSON_READ_TYPE_U16 = 3, + JSON_READ_TYPE_S16 = 4, + JSON_READ_TYPE_U32 = 5, + JSON_READ_TYPE_S32 = 6, + JSON_READ_TYPE_F32 = 7, + JSON_READ_TYPE_F64 = 8, + JSON_READ_TYPE_GRAPH_RUNTIME_NODE = 9, + JSON_READ_TYPE_GRAPH_RUNTIME_NODE_ENTRY = 10, + JSON_READ_TYPE_GRAPH_RUNTIME_GRAPH_ATTR = 11 +}; + +/*! + * \brief Lightweight JSON Reader to read any STL compositions and structs. + * The user need to know the schema of the + */ +typedef struct json_reader_t { + /*! \brief internal reader string */ + char is_[TVM_CRT_MAX_JSON_LENGTH]; + char * isptr; + /*! \brief "\\r" counter */ + size_t line_count_r_; + /*! \brief "\\n" counter */ + size_t line_count_n_; + /*! + * \brief record how many element processed in + * current array/object scope. + */ + Seq scope_counter_; + + char (*NextChar)(struct json_reader_t * reader); + char (*NextNonSpace)(struct json_reader_t * reader); + char (*PeekNextChar)(struct json_reader_t * reader); + char (*PeekNextNonSpace)(struct json_reader_t * reader); + int (*ReadUnsignedInteger)(struct json_reader_t * reader, unsigned int * out_value); + int (*ReadInteger)(struct json_reader_t * reader, int64_t * out_value); + int (*ReadString)(struct json_reader_t * reader, char * out_value); + void (*BeginArray)(struct json_reader_t * reader); + void (*BeginObject)(struct json_reader_t * reader); + bool (*NextObjectItem)(struct json_reader_t * reader, char * out_key); + bool (*NextArrayItem)(struct json_reader_t * reader); +} JSONReader; + +typedef void (*ReadFunction)(JSONReader *reader, void *addr); + +/*! \brief internal data entry */ +struct JSONObjectReadHelperEntry { + /*! \brief the reader function */ + ReadFunction func; + /*! \brief the address to read */ + void *addr; + /*! \brief whether it is optional */ + bool optional; +}; + +/*! + * \brief Helper class to read JSON into a class or struct object. + * \code + * struct Param { + * string name; + * int value; + * // define load function from JSON + * inline void Load(dmlc::JSONReader *reader) { + * dmlc::JSONStructReadHelper helper; + * helper.DeclareField("name", &name); + * helper.DeclareField("value", &value); + * helper.ReadAllFields(reader); + * } + * }; + * \endcode + */ +struct JSONObjectReadHelper { + /*! + * \brief Read in all the declared fields. + * \param reader the JSONReader to read the json. + */ + void (*ReadAllFields)(JSONReader *reader); + /*! + * \brief The internal reader function. + * \param reader The reader to read. + * \param addr The memory address to read. + */ + void (*ReaderFunction)(JSONReader *reader, void *addr); +}; + +#define DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName) \ + static DMLC_ATTRIBUTE_UNUSED ::dmlc::json::AnyJSONManager& \ + __make_AnyJSONType ## _ ## KeyName ## __ + +/*! + * \def DMLC_JSON_ENABLE_ANY + * \brief Macro to enable save/load JSON of dmlc:: whose actual type is Type. + * Any type will be saved as json array [KeyName, content] + * + * \param Type The type to be registered. + * \param KeyName The Type key assigned to the type, must be same during load. + */ +#define DMLC_JSON_ENABLE_ANY(Type, KeyName) \ + DMLC_STR_CONCAT(DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName), __COUNTER__) = \ + ::dmlc::json::AnyJSONManager::Global()->EnableType(#KeyName) \ + +// implementations of JSONReader + +/*! + * \brief Takes the next char from the input source. + * \return the next character. + */ +static inline char JSONReader_NextChar(JSONReader * reader) { + char ch = reader->isptr[0]; + reader->isptr += 1; + return ch; +} + +/*! + * \brief Returns the next char from the input source. + * \return the next character. + */ +static inline char JSONReader_PeekNextChar(JSONReader * reader) { + return reader->isptr[0]; +} + +/*! + * \brief Read next nonspace character. + * \return the next nonspace character. + */ +static inline char JSONReader_NextNonSpace(JSONReader * reader) { + int ch; + do { + ch = reader->NextChar(reader); + if (ch == '\n') { ++(reader->line_count_n_); } + if (ch == '\r') { ++(reader->line_count_r_); } + } while (isspace(ch)); + return ch; +} + +/*! + * \brief Read just before next nonspace but not read that. + * \return the next nonspace character. + */ +static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { + int ch; + while (true) { + ch = reader->PeekNextChar(reader); + if (ch == '\n') { ++(reader->line_count_n_); } + if (ch == '\r') { ++(reader->line_count_r_); } + if (!isspace(ch)) break; + reader->NextChar(reader); + } + return ch; +} + +/*! + * \brief Parse next JSON string. + * \param out_str the output string. + * \throw dmlc::Error when next token is not string + */ +static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { + int status = TVM_STATUS_SUCCESS; + char ch = reader->NextNonSpace(reader); + char output[128]; + uint32_t output_counter = 0; + memset(output, 0, 128); + while (true) { + ch = reader->NextChar(reader); + if (ch == '\\') { + char sch = reader->NextChar(reader); + switch (sch) { + case 'r': strcat(output, "\r"); break; + case 'n': strcat(output, "\n"); break; + case '\\': strcat(output, "\\"); break; + case 't': strcat(output, "\t"); break; + case '\"': strcat(output, "\""); break; + default: LOGE("unknown string escape \%c", sch); + } + } else { + if (ch == '\"') { break; } + if (strlen(output) >= 127) { + LOGE("Error: detected buffer overflow."); + status = TVM_STATUS_FAILURE; + break; + } + strncat(output, &ch, 1); + output_counter++; + if (output_counter >= 127) { + LOGE("Error: string size greater than 128."); + status = TVM_STATUS_FAILURE; + break; + } + } + if (ch == EOF || ch == '\r' || ch == '\n') { + LOGE("Error at line X, Expect \'\"\' but reach end of line"); + } + } + strcpy(out_str, output); + return status; +} + +static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { + int status = TVM_STATUS_SUCCESS; + char* endptr; + const char* icstr = reader->isptr; // ->data_; + unsigned int number = strtol(icstr, &endptr, 10); + reader->isptr += endptr - icstr; + *out_value = number; + return status; +} + + +static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { + int status = TVM_STATUS_SUCCESS; + char* endptr; + const char* icstr = reader->isptr; // ->data_; + int64_t number = strtol(icstr, &endptr, 10); + reader->isptr += endptr - icstr; + *out_value = number; + return status; +} + +/*! + * \brief Begin parsing an object. + * \code + * string key; + * // value can be any type that is json serializable. + * string value; + * reader->BeginObject(); + * while (reader->NextObjectItem(&key)) { + * // do somthing to key value + * reader->Read(&value); + * } + * \endcode + */ +static inline void JSONReader_BeginObject(JSONReader * reader) { + int ch = reader->NextNonSpace(reader); + if (!(ch == '{')) { + LOGE("Error at line X, Expect \'{\' but got \'%c\'", ch); + } + Seq * scope_counter_ = &(reader->scope_counter_); + scope_counter_->push_back(scope_counter_, 0); +} + +/*! + * \brief Try to move to next object item. + * If this call is successful, user can proceed to call + * reader->Read to read in the value. + * \param out_key the key to the next object. + * \return true if the read is successful, false if we are at end of the object. + */ +static inline bool JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { + bool next = true; + Seq * scope_counter_ = &(reader->scope_counter_); + if (scope_counter_->back(scope_counter_)[0] != 0) { + int ch = reader->NextNonSpace(reader); + if (ch == EOF) { + next = false; + } else if (ch == '}') { + next = false; + } else { + if (ch != ',') { + LOGE("Error at line X, JSON object expect \'}\' or \',\' but got \'%c\'", ch); + } + } + } else { + int ch = reader->PeekNextNonSpace(reader); + if (ch == '}') { + reader->NextChar(reader); + next = false; + } + } + if (!next) { + scope_counter_->pop_back(scope_counter_); + return false; + } else { + scope_counter_->back(scope_counter_)[0] += 1; + reader->ReadString(reader, out_key); + int ch = reader->NextNonSpace(reader); + if (ch != ':') { + LOGE("Error at line X, Expect \':\' but get \'%c\'", ch); + } + return true; + } +} + +/*! + * \brief Begin parsing an array. + * \code + * // value can be any type that is json serializable. + * string value; + * reader->BeginArray(); + * while (reader->NextArrayItem(&value)) { + * // do somthing to value + * } + * \endcode + */ +static inline void JSONReader_BeginArray(JSONReader * reader) { + int ch = reader->NextNonSpace(reader); + if (ch != '[') { + LOGE("Error at line X, Expect \'[\' but get \'%c\'", ch); + } + Seq * scope_counter_ = &(reader->scope_counter_); + scope_counter_->push_back(scope_counter_, 0); +} + +/*! + * \brief Try to read the next element in the array. + * If this call is successful, user can proceed to call + * reader->Read to read in the value. + * \return true if the read is successful, false if we are at end of the array. + */ +static inline bool JSONReader_NextArrayItem(JSONReader * reader) { + bool next = true; + Seq * scope_counter_ = &(reader->scope_counter_); + if (scope_counter_->back(scope_counter_)[0] != 0) { + int ch = reader->NextNonSpace(reader); + if (ch == EOF) { + next = false; + } else if (ch == ']') { + next = false; + } else { + if (ch != ',') { + LOGE("Error at line X, JSON object expect \']\' or \',\' but got \'%c\'", ch); + } + } + } else { + int ch = reader->PeekNextNonSpace(reader); + if (ch == ']') { + reader->NextChar(reader); + next = false; + } + } + if (!next) { + scope_counter_->pop_back(scope_counter_); + return false; + } else { + scope_counter_->back(scope_counter_)[0] += 1; + return true; + } +} + +/*! + * \brief Constructor. + * \param is the input source. + */ +static inline JSONReader JSONReader_Create(const char * is) { + JSONReader reader; // = (JSONReader*)malloc(sizeof(JSONReader)); + memset(&reader, 0, sizeof(JSONReader)); + reader.scope_counter_ = SeqCreate(); + reader.NextChar = JSONReader_NextChar; + reader.PeekNextChar = JSONReader_PeekNextChar; + reader.NextNonSpace = JSONReader_NextNonSpace; + reader.PeekNextNonSpace = JSONReader_PeekNextNonSpace; + reader.ReadString = JSONReader_ReadString; + reader.ReadUnsignedInteger = JSONReader_ReadUnsignedInteger; + reader.ReadInteger = JSONReader_ReadInteger; + reader.BeginArray = JSONReader_BeginArray; + reader.BeginObject = JSONReader_BeginObject; + reader.NextArrayItem = JSONReader_NextArrayItem; + reader.NextObjectItem = JSONReader_NextObjectItem; + strcpy(reader.is_, is); + reader.isptr = reader.is_; + return reader; +} + +#endif // LOAD_JSON_H_ diff --git a/src/runtime/crt/module.h b/src/runtime/crt/module.h new file mode 100644 index 000000000000..a548aee02685 --- /dev/null +++ b/src/runtime/crt/module.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \file src/runtime/crt/module.h + * \brief Runtime container of the functions generated by TVM, + * This is used to support dynamically link, load and save + * functions from different convention under unified API. + */ +#ifndef TVM_RUNTIME_MODULE_H_ +#define TVM_RUNTIME_MODULE_H_ + +#include +#include "c_runtime_api.h" +#include "common.h" + +struct packed_func_t; +typedef struct packed_func_t PackedFunc; + +/*! + * \brief Module container of TVM. + */ +typedef struct module_t { + /*! + * \brief Get packed function from current module by name. + * + * \param name The name of the function. + * \param query_imports Whether also query dependency modules. + * \return The result function. + * This function will return PackedFunc(nullptr) if function do not exist. + * \note Implemented in packed_func.cc + */ + void (*GetFunction)(const char * name, PackedFunc * pf); + void (*set_input)(const struct module_t * mod, const char * name, DLTensor * data); + void (*load_params)(const struct module_t * mod, const TVMByteArray * params_arr); + void (*run)(const struct module_t * mod); +} Module; + +#endif // TVM_RUNTIME_MODULE_H_ diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c new file mode 100644 index 000000000000..9afa36f81bc7 --- /dev/null +++ b/src/runtime/crt/ndarray.c @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * Copyright (c) 2017 by Contributors + * \file ndarray.c + * \brief NDArray container infratructure. + */ + +#include "common.h" +#include "ndarray.h" +#include "c_runtime_api.h" +#include "c_backend_api.h" +#include "c_api_common.h" + +NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype) { + uint32_t ndim = Shape_CountNonZero(shape); + NDArray ret = NDArray_Create(ndim, shape, dtype, arr->dl_tensor.ctx); + ret.dl_tensor.data = arr->dl_tensor.data; + return ret; +} + +int TVMArrayAlloc(const tvm_index_t* shape, + uint8_t ndim, + uint8_t dtype_code, + uint8_t dtype_bits, + uint16_t dtype_lanes, + uint8_t device_type, + uint8_t device_id, + TVMArrayHandle out) { + API_BEGIN(); + uint32_t idx = 0; + DLDataType dtype; + dtype.code = dtype_code; + dtype.bits = dtype_bits; + dtype.lanes = dtype_lanes; + DLContext ctx; + ctx.device_type = device_type; + ctx.device_id = device_id; + out->ctx = ctx; + out->ndim = ndim; + out->dtype = dtype; + uint32_t bytes = (dtype_bits + 7) / 8; + uint32_t size = 1; + for (idx = 0; idx < ndim; idx++) { + size *= shape[idx]; + } + out->data = TVMBackendAllocWorkspace(device_type, device_id, size, dtype_code, dtype_bits); + memset(out->data, 0, size * bytes); + for (idx = 0; idx < ndim; idx++) { + out->shape[idx] = shape[idx]; + out->strides = 0; + } + out->byte_offset = 0; + API_END(); +} + +int TVMArrayFree(TVMArrayHandle handle) { + API_BEGIN(); + API_END(); +} + diff --git a/src/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h new file mode 100644 index 000000000000..d919d55f323c --- /dev/null +++ b/src/runtime/crt/ndarray.h @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \file tvm/runtime/ndarray.h + * \brief Abstract device memory management API + */ +#ifndef TVM_RUNTIME_NDARRAY_H_ +#define TVM_RUNTIME_NDARRAY_H_ + +#include "c_runtime_api.h" +#include "c_backend_api.h" +#include "common.h" +#include "dlpack.h" + +/*! \brief Magic number for NDArray file */ +static const uint64_t kTVMNDArrayMagic = 0xDD5E40F096B4A13F; + +typedef struct ndarray_t { + DLTensor dl_tensor; +} NDArray; + +NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype); + +static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx) { + NDArray ret; + memset(&ret, 0, sizeof(NDArray)); + ret.dl_tensor.ndim = ndim; + memcpy(ret.dl_tensor.shape, shape, sizeof(int64_t)*ndim); + ret.dl_tensor.dtype = dtype; + ret.dl_tensor.ctx = ctx; + ret.dl_tensor.data = 0; + return ret; +} + +static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx) { + NDArray ret = NDArray_Create(ndim, shape, dtype, ctx); + int64_t num_elems = 1; + int elem_bytes = (dtype.bits + 7) / 8; + uint32_t idx; + for (idx = 0; idx < ret.dl_tensor.ndim; ++idx) { + num_elems *= shape[idx]; + } + ret.dl_tensor.data = TVMBackendAllocWorkspace(kDLCPU, 0, num_elems, dtype.code, dtype.bits); + memset(ret.dl_tensor.data, 0, num_elems * elem_bytes); + return ret; +} + +static inline int NDArray_Load(NDArray * ret, const char ** strm) { + API_BEGIN(); + uint64_t header, reserved; + header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); + if (header != kTVMNDArrayMagic) { + LOGE("Invalid DLTensor file format\n"); + status = TVM_STATUS_FAILURE; + } + reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); + DLContext ctx; + uint32_t ndim; + DLDataType dtype; + ctx = ((DLContext*)*strm)[0]; *strm += sizeof(ctx); + ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); + dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); + if ((ndim <= 0) || (ndim > TVM_CRT_MAX_NDIM)) { + LOGE("Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); + status = TVM_STATUS_FAILURE; + } + if (ctx.device_type != kDLCPU) { + LOGE("Invalid DLTensor context: can only save as CPU tensor\n"); + status = TVM_STATUS_FAILURE; + } + int64_t shape[TVM_CRT_MAX_NDIM]; // [ndim]; + uint32_t idx; + if (ndim != 0) { + for (idx = 0; idx < ndim; idx++){ + shape[idx] = ((int64_t*)*strm)[0]; *strm += sizeof(shape[idx]); + } + } + *ret = NDArray_Empty(ndim, shape, dtype, ctx); + int64_t num_elems = 1; + int elem_bytes = (ret->dl_tensor.dtype.bits + 7) / 8; + for (idx = 0; idx < ret->dl_tensor.ndim; ++idx) { + num_elems *= ret->dl_tensor.shape[idx]; + } + int64_t data_byte_size; + data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); + if (!(data_byte_size == num_elems * elem_bytes)) { + LOGE("invalid DLTensor file format: data_byte_size=%ld, while num_elems*elem_bytes=%ld", + data_byte_size, (num_elems * elem_bytes)); + status = TVM_STATUS_FAILURE; + } + memcpy(ret->dl_tensor.data, *strm, data_byte_size); + *strm += data_byte_size; + API_END(); +} + +#endif // TVM_RUNTIME_NDARRAY_H_ From 63ea62f265f79f54cf0d89ae4382846fd0cd4eb3 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 10 Feb 2020 23:21:47 +0800 Subject: [PATCH 02/31] working on bundle_deploy_c demo --- apps/bundle_deploy_c/Makefile | 56 ++++++++++++++++++++++++++++ apps/bundle_deploy_c/README.md | 53 +++++++++++++++++++++++++++ apps/bundle_deploy_c/build_model.py | 57 +++++++++++++++++++++++++++++ src/runtime/crt/graph_runtime.c | 6 +-- src/runtime/crt/graph_runtime.h | 4 +- src/runtime/crt/load_json.c | 1 - src/runtime/crt/load_json.h | 21 ++++++++++- src/runtime/crt/module.h | 4 +- src/runtime/crt/ndarray.c | 1 - 9 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 apps/bundle_deploy_c/Makefile create mode 100644 apps/bundle_deploy_c/README.md create mode 100644 apps/bundle_deploy_c/build_model.py diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile new file mode 100644 index 000000000000..57e484379a4e --- /dev/null +++ b/apps/bundle_deploy_c/Makefile @@ -0,0 +1,56 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# Makefile Example to bundle TVM modules. + +TVM_ROOT=$(shell cd ../..; pwd) +DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core +PKG_CFLAGS = -std=c++14 -O2 -fPIC\ + -I${TVM_ROOT}/include\ + -I${DMLC_CORE}/include\ + -I${TVM_ROOT}/3rdparty/dlpack/include + +PKG_LDFLAGS = -pthread + +build_dir := build + +test: $(build_dir)/demo $(build_dir)/bundle.so + $(build_dir)/demo $(build_dir)/bundle.so + +$(build_dir)/demo: demo.cc + @mkdir -p $(@D) + $(CXX) $(PKG_CFLAGS) -o $@ $^ -ldl + +# Serialize our graph.json file. +$(build_dir)/graph.json.cc: $(build_dir)/graph.json + xxd -i $^ > $@ + +# Serialize our params.bin file. +$(build_dir)/params.bin.cc: $(build_dir)/params.bin + xxd -i $^ > $@ + +$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin: build_model.py + python3 $< -o $(build_dir) + +# Build our bundle against the serialized bundle.cc API, the runtime.cc API, and +# the serialized graph.json and params.bin +$(build_dir)/bundle.so: bundle.cc runtime.cc $(build_dir)/model.o $(build_dir)/graph.json.cc $(build_dir)/params.bin.cc + @mkdir -p $(@D) + $(CXX) -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + +clean: + rm -r $(build_dir) diff --git a/apps/bundle_deploy_c/README.md b/apps/bundle_deploy_c/README.md new file mode 100644 index 000000000000..6be9c4f91340 --- /dev/null +++ b/apps/bundle_deploy_c/README.md @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + +How to Bundle TVM Modules +========================= + +This folder contains an example on how to bundle a TVM module (with the required +interpreter runtime modules such as `runtime::GraphRuntime`, the graph JSON, and +the params) into a single, self-contained shared object (`bundle.so`) which +exposes a C API wrapping the appropriate `runtime::GraphRuntime` instance. + +This is useful for cases where we'd like to avoid deploying the TVM runtime +components to the target host in advance - instead, we simply deploy the bundled +shared-object to the host, which embeds both the model and the runtime +components. The bundle should only depend on libc/libc++. + +It also contains an example code (`demo.cc`) to load this shared object and +invoke the packaged TVM model instance. This is a dependency-free binary that +uses the functionality packaged in `bundle.so` (which means that `bundle.so` can +be deployed lazily at runtime, instead of at compile time) to invoke TVM +functionality. + +Type the following command to run the sample code under the current folder, +after building TVM first. + +```bash +make demo +``` + +This will: + +- Download the mobilenet0.25 model from the MXNet Gluon Model Zoo +- Compile the model with NNVM +- Build a `bundle.so` shared object containing the model specification and + parameters +- Build a `demo` executable that `dlopen`'s `bundle.so`, instantiates the + contained graph runtime, and invokes the `GraphRuntime::Run` function on a + random input, then prints the output tensor to `stderr`. diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py new file mode 100644 index 000000000000..de9e73522ca2 --- /dev/null +++ b/apps/bundle_deploy_c/build_model.py @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +"""Creates a simple TVM modules.""" + +import argparse +import os +from tvm import relay +import tvm +import logging + + +def main(): + logging.basicConfig(level=logging.INFO) + + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--out-dir', default='.') + opts = parser.parse_args() + + dshape = (1, 3, 224, 224) + from mxnet.gluon.model_zoo.vision import get_model + block = get_model('mobilenet0.25', pretrained=True) + shape_dict = {'data': dshape} + mod, params = relay.frontend.from_mxnet(block, shape_dict) + func = mod["main"] + func = relay.Function(func.params, relay.nn.softmax(func.body), None, func.type_params, func.attrs) + + with relay.build_config(opt_level=3): + graph, lib, params = relay.build( + func, 'llvm --system-lib', params=params) + + build_dir = os.path.abspath(opts.out_dir) + if not os.path.isdir(build_dir): + os.makedirs(build_dir) + + lib.save(os.path.join(build_dir, 'model.o')) + with open(os.path.join(build_dir, 'graph.json'), 'w') as f_graph_json: + f_graph_json.write(graph) + with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: + f_params.write(relay.save_param_dict(params)) + + +if __name__ == '__main__': + main() diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 709acc1ed2e3..fb16f24887ed 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -6,9 +6,9 @@ * to you 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 @@ -18,8 +18,8 @@ */ /*! - * Copyright (c) 2017 by Contributors * \file graph_runtime.c + * \brief implement graph runtime in pure C */ #include "graph_runtime.h" #include "c_api_common.h" diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index 97e65cd7b59b..6e151b3d4e01 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -18,10 +18,8 @@ */ /*! - * Copyright (c) 2017 by Contributors - * - * \brief Tiny graph runtime that can run graph containing only tvm PackedFunc. * \file graph_runtime.h + * \brief Tiny graph runtime that can run graph containing only tvm PackedFunc. */ #ifndef TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ #define TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index a3dee0943780..bc58c9e35fe7 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -18,7 +18,6 @@ */ /*! - * Copyright (c) 2016 by Contributors * \file saveload_json.cc * \brief Save and load graph to/from JSON file. */ diff --git a/src/runtime/crt/load_json.h b/src/runtime/crt/load_json.h index 40a9ceba5e19..b88d2fa104de 100644 --- a/src/runtime/crt/load_json.h +++ b/src/runtime/crt/load_json.h @@ -1,8 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + /*! - * Copyright (c) 2015 by Contributors * \file json.h * \brief Lightweight JSON Reader that read save into C++ data structs. - * This includes STL composites and structures. */ #ifndef LOAD_JSON_H_ #define LOAD_JSON_H_ diff --git a/src/runtime/crt/module.h b/src/runtime/crt/module.h index a548aee02685..324660a5faf8 100644 --- a/src/runtime/crt/module.h +++ b/src/runtime/crt/module.h @@ -19,9 +19,7 @@ /*! * \file src/runtime/crt/module.h - * \brief Runtime container of the functions generated by TVM, - * This is used to support dynamically link, load and save - * functions from different convention under unified API. + * \brief Runtime container of the functions */ #ifndef TVM_RUNTIME_MODULE_H_ #define TVM_RUNTIME_MODULE_H_ diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index 9afa36f81bc7..159ffe6d23d6 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -18,7 +18,6 @@ */ /*! - * Copyright (c) 2017 by Contributors * \file ndarray.c * \brief NDArray container infratructure. */ From dfffa76aea6106ff9eabbfa164f7c0a20db04ece Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Tue, 11 Feb 2020 12:42:24 +0800 Subject: [PATCH 03/31] move header files into include dir --- apps/bundle_deploy_c/Makefile | 27 ++- apps/bundle_deploy_c/bundle.c | 79 ++++++++ apps/bundle_deploy_c/demo.c | 150 +++++++++++++++ apps/bundle_deploy_c/runtime.c | 45 +++++ include/tvm/runtime/crt/common.h | 169 ++++++++++++++++ .../tvm}/runtime/crt/graph_runtime.h | 12 +- {src => include/tvm}/runtime/crt/load_json.h | 0 {src => include/tvm}/runtime/crt/module.h | 4 +- {src => include/tvm}/runtime/crt/ndarray.h | 10 +- include/tvm/runtime/crt/packed_func.h | 182 ++++++++++++++++++ 10 files changed, 656 insertions(+), 22 deletions(-) create mode 100644 apps/bundle_deploy_c/bundle.c create mode 100644 apps/bundle_deploy_c/demo.c create mode 100644 apps/bundle_deploy_c/runtime.c create mode 100644 include/tvm/runtime/crt/common.h rename {src => include/tvm}/runtime/crt/graph_runtime.h (98%) rename {src => include/tvm}/runtime/crt/load_json.h (100%) rename {src => include/tvm}/runtime/crt/module.h (95%) rename {src => include/tvm}/runtime/crt/ndarray.h (95%) create mode 100644 include/tvm/runtime/crt/packed_func.h diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 57e484379a4e..5ad87395c2dd 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -17,12 +17,21 @@ # Makefile Example to bundle TVM modules. +# Configure runtime +DEBUG = 0 +MAX_NDIM = 6 +MAX_ARGS = 10 + +# Setup build environment TVM_ROOT=$(shell cd ../..; pwd) DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CFLAGS = -std=c++14 -O2 -fPIC\ - -I${TVM_ROOT}/include\ - -I${DMLC_CORE}/include\ - -I${TVM_ROOT}/3rdparty/dlpack/include +PKG_CFLAGS = -std=c99 -O2 -fPIC \ + -I${TVM_ROOT}/include \ + -I${DMLC_CORE}/include \ + -I${TVM_ROOT}/3rdparty/dlpack/include \ + -DTVM_CRT_DEBUG=${DEBUG} \ + -DTVM_CRT_MAX_NDIM=${MAX_NDIM} \ + -DTVM_CRT_MAX_ARGS=${MAX_ARGS} PKG_LDFLAGS = -pthread @@ -33,14 +42,14 @@ test: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/demo: demo.cc @mkdir -p $(@D) - $(CXX) $(PKG_CFLAGS) -o $@ $^ -ldl + gcc $(PKG_CFLAGS) -o $@ $^ -ldl # Serialize our graph.json file. -$(build_dir)/graph.json.cc: $(build_dir)/graph.json +$(build_dir)/graph.json.c: $(build_dir)/graph.json xxd -i $^ > $@ # Serialize our params.bin file. -$(build_dir)/params.bin.cc: $(build_dir)/params.bin +$(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin: build_model.py @@ -48,9 +57,9 @@ $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin: build_mode # Build our bundle against the serialized bundle.cc API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.cc runtime.cc $(build_dir)/model.o $(build_dir)/graph.json.cc $(build_dir)/params.bin.cc +$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.c $(build_dir)/params.bin.c @mkdir -p $(@D) - $(CXX) -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) clean: rm -r $(build_dir) diff --git a/apps/bundle_deploy_c/bundle.c b/apps/bundle_deploy_c/bundle.c new file mode 100644 index 000000000000..33f86645c59b --- /dev/null +++ b/apps/bundle_deploy_c/bundle.c @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 */ +/* #include */ +/* #include */ +#include + +extern unsigned char build_graph_json[]; +extern unsigned int build_graph_json_len; +extern unsigned char build_params_bin[]; +extern unsigned int build_params_bin_len; + +#define TVM_BUNDLE_FUNCTION __attribute__((visibility("default"))) + +/* extern "C" { */ + +TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { + char * json_data = build_graph_json; + /* memset(json_data, 0, build_graph_json_len + 1); */ + /* memcpy(json_data, build_graph_json, build_graph_json_len); */ + + int device_type = kDLCPU; + int device_id = 0; + /* tvm::runtime::Module mod = */ + /* (*tvm::runtime::Registry::Get("tvm.graph_runtime.create"))( */ + /* json_data, mod_syslib, device_type, device_id); */ + TVMByteArray params; + params.data = build_params_bin; + params.size = build_params_bin_len; + + TVMContext ctx; + ctx.device_type = device_type; + ctx.device_id = device_id; + GraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); + + /* mod.GetFunction("load_params")(params); */ + runtime->LoadParams(runtime, params.data, params.size); + + /* return new tvm::runtime::Module(mod); */ + return runtime; +} + +TVM_BUNDLE_FUNCTION void tvm_runtime_destroy(GraphRuntime * runtime) { + /* delete reinterpret_cast(handle); */ +} + +TVM_BUNDLE_FUNCTION void tvm_runtime_set_input(GraphRuntime * runtime, const char * name, + void * tensor) { + /* reinterpret_cast(handle)->GetFunction("set_input")( */ + /* name, reinterpret_cast(tensor)); */ +} + +TVM_BUNDLE_FUNCTION void tvm_runtime_run(GraphRuntime * runtime) { + /* reinterpret_cast(handle)->GetFunction("run")(); */ +} + +TVM_BUNDLE_FUNCTION void tvm_runtime_get_output(GraphRuntime * runtime, int32_t index, + void * tensor) { + /* reinterpret_cast(handle)->GetFunction("get_output")( */ + /* index, reinterpret_cast(tensor)); */ +} +/* } */ diff --git a/apps/bundle_deploy_c/demo.c b/apps/bundle_deploy_c/demo.c new file mode 100644 index 000000000000..06e959e6a170 --- /dev/null +++ b/apps/bundle_deploy_c/demo.c @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "tvm/runtime/c_runtime_api.h" +#include +#include //dlopen +#include + +int main(int argc, char **argv) { + /* assert(argc == 2 && "Usage: demo "); */ + /* auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); */ + /* assert(bundle); */ + + // json graph + const char * json_fn = "build/deploy.min.json"; + const char * params_fn = "build/deploy.params"; + + FILE * json_in = fopen(json_fn, "rt"); + /* std::string json_data((std::istreambuf_iterator(json_in)), std::istreambuf_iterator()); */ + /* json_in.close(); */ + EXPECT_NE(json_in, (void*)0); + if (json_in == (void*)0) { exit(-1); } + size_t json_size = findSize(json_fn); + char * json_data = (char*)malloc(json_size+1); + fread(json_data, json_size, 1, json_in); + fclose(json_in); + json_in = 0; + + // parameters in binary + FILE * params_in = fopen(params_fn, "rb"); + EXPECT_NE(params_in, (void*)0); + if (params_in == (void*)0) { exit(-1); } + /* std::string params_data((std::istreambuf_iterator(params_in)), std::istreambuf_iterator()); */ + /* params_in.close(); */ + size_t params_size = findSize(params_fn); + char * params_data = (char*)malloc(params_size); + fread(params_data, params_size, 1, params_in); + fclose(params_in); + params_in = 0; + + // parameters need to be TVMByteArray type to indicate the binary data + TVMByteArray params_arr; + params_arr.data = params_data; + params_arr.size = params_size; + + int dtype_code = kDLFloat; + int dtype_bits = 32; + int dtype_lanes = 1; + int device_type = kDLCPU; + int device_id = 0; + + // get global function module for graph runtime + TVMContext ctx; + ctx.device_type = kDLCPU; + ctx.device_id = 0; + { + JSONReader reader; + EXPECT_GE(sizeof(reader.is_), json_size); + } + GraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); + /* typedef Module * (*TVMGraphRuntimeCreateFunc)(char *, void *, int, int) ; */ + /* TVMFunctionHandle graph_runtime; */ + /* TVMGraphRuntimeCreateFunc graph_runtime; */ + /* TVMFuncGetGlobal("tvm.graph_runtime.create", (TVMFunctionHandle*)&graph_runtime); */ + /* Module * mod = graph_runtime(json_data, mod_syslib, device_type, device_id); */ + /* Module * mod = graph_runtime->pushArg(json_data)->pushArg(mod_syslib) */ + /* ->pushArg(device_type)->pushArg(device_id)->invoke()->asModule(); */ + + DLTensor x; + int in_ndim = 4; + int64_t in_shape[4] = {1, 3, 224, 224}; + TVMArrayAlloc(in_shape, in_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &x); + + // load image data saved in binary + FILE * data_fin = fopen("cat.bin", "rb"); + /* data_fin.read(static_cast(x->data), 3 * 224 * 224 * 4); */ + int64_t data_size = findSize("cat.bin"); + /* char * data_data = (char*)malloc(data_size); */ + if (data_size != (in_shape[0]*in_shape[1]*in_shape[2]*in_shape[3]*4)) { + LOGE("wrong file size: %d != %d", (int32_t)data_size, (int32_t)(in_shape[0]*in_shape[1]*in_shape[2]*in_shape[3]*4)); + } + fread(x.data, data_size, 1, data_fin); + fclose(data_fin); + data_fin = 0; + + // get the function from the module(set input data) + // TVMSetInputCFunc set_input = mod->GetFunction("set_input"); + // mod->set_input(mod, "data", &x); + runtime->SetInput(runtime, "data", &x); + + // get the function from the module(load patameters) + // TVMLoadParamsCFunc load_params = mod->GetFunction("load_params"); + runtime->LoadParams(runtime, params_arr.data, params_arr.size); + + // get the function from the module(run it) + // TVMRunCFunc run = mod->GetFunction("run"); + runtime->Run(runtime); + +// for (int idx = 0; idx < 1000; idx++) { +// LOGI("%d: %.3f", idx, ((float*)runtime->op_execs[263].args.values[1].v_handle->data)[idx]); +// } + + DLTensor y; + int out_ndim = 1; + int64_t out_shape[1] = {1000, }; + TVMArrayAlloc(out_shape, out_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &y); + + // get the function from the module(get output data) + // TVMPackedCFunc get_output = mod->GetFunction("get_output"); + /* get_output(0, y); */ + runtime->GetOutput(runtime, 0, &y); + + // get the maximum position in output vector + // auto y_iter = static_cast(y->data); + // auto max_iter = std::max_element(y_iter, y_iter + 1000); + // auto max_index = std::distance(y_iter, max_iter); + float max_iter = - FLT_MAX; + int32_t max_index = -1; + float * y_iter = (float*)y.data; + // qsort(y_iter, 1000, sizeof(float), compareFloat); + for (int32_t idx = 0; idx < 1000; idx++) { + if (y_iter[idx] > max_iter) { + max_iter = y_iter[idx]; + max_index = idx; + } + } + + LOGI("The maximum position in output vector is: %d, with max-value %f.", max_index, max_iter); + + TVMArrayFree(&y); + TVMArrayFree(&x); + + return 0; +} diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c new file mode 100644 index 000000000000..12d172e2fab0 --- /dev/null +++ b/apps/bundle_deploy_c/runtime.c @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +/* #include */ +/* #include */ +#include +#include +#include + +/* #include "../../src/runtime/c_runtime_api.cc" */ +/* #include "../../src/runtime/cpu_device_api.cc" */ +/* #include "../../src/runtime/workspace_pool.cc" */ +/* #include "../../src/runtime/library_module.cc" */ +/* #include "../../src/runtime/module.cc" */ +/* #include "../../src/runtime/registry.cc" */ +/* #include "../../src/runtime/file_util.cc" */ +/* #include "../../src/runtime/threading_backend.cc" */ +/* #include "../../src/runtime/thread_pool.cc" */ +/* #include "../../src/runtime/ndarray.cc" */ +/* #include "../../src/runtime/object.cc" */ +/* #include "../../src/runtime/system_library.cc" */ +/* #include "../../src/runtime/graph/graph_runtime.cc" */ + +#include "../../src/runtime/crt/graph_runtime.c" +#include "../../src/runtime/crt/load_json.c" +#include "../../src/runtime/crt/ndarray.c" + diff --git a/include/tvm/runtime/crt/common.h b/include/tvm/runtime/crt/common.h new file mode 100644 index 000000000000..7e63632ec539 --- /dev/null +++ b/include/tvm/runtime/crt/common.h @@ -0,0 +1,169 @@ +#ifndef COMMON_H_ +#define COMMON_H_ + +// #include "config.h" + +#include +#include +#include +#include +#include + +#ifndef __cplusplus + +/* typedef unsigned int size_t; */ +typedef unsigned char bool; +static const unsigned char false = 0; +static const unsigned char true = 1; + +#define nullptr ((void*)0) + +#endif // __cplusplus + +#define TVM_STATUS_SUCCESS (0) +#define TVM_STATUS_FAILURE (-1) + +#define API_BEGIN() int status; do { status = TVM_STATUS_SUCCESS; } while(false) +#define API_END() return status + +#if defined(WIN32) || defined(_WIN32) +#include +#ifndef __func__ +#define __func__ __FUNCTION__ +#endif +#define LOGE(fmt,...) \ + do { \ + char msgbuf[1024];sprintf(msgbuf,"ERROR: " fmt,##__VA_ARGS__); \ + MessageBoxA(NULL,msgbuf,"ERROR",MB_ICONERROR|MB_OK); \ + }while(0) +#define LOGW(fmt,...) \ + do { \ + char msgbuf[1024];sprintf(msgbuf,"WARNING: " fmt,##__VA_ARGS__); \ + MessageBoxA(NULL,msgbuf,"WARNING",MB_ICONWARNING|MB_OK); \ + }while(0) +#define LOGI(fmt,...) \ + do { \ + char msgbuf[1024];sprintf(msgbuf,"INFO: " fmt,##__VA_ARGS__); \ + MessageBoxA(NULL,msgbuf,"INFO",MB_ICONINFORMATION|MB_OK); \ + }while(0) +#elif defined(ANDROID) +#define LOG_TAG "TVMCRT" +#define LOGE(fmt,...) \ + do { \ + __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, \ + "ERROR: " fmt,##__VA_ARGS__); \ + }while(0) +#define LOGW(fmt,...) \ + do { \ + __android_log_print(ANDROID_LOG_WARN,LOG_TAG, \ + "WARNING: " fmt,##__VA_ARGS__); \ + }while(0) +#define LOGI(fmt,...) \ + do { \ + __android_log_print(ANDROID_LOG_INFO,LOG_TAG, \ + "INFO: " fmt,##__VA_ARGS__); \ + }while(0) +#elif defined(__linux__) || defined(__APPLE__) +#define LOGE(fmt,...) \ + do { \ + fprintf(stderr,"%s:%d: error: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ + exit(-1); \ + }while(0) +#define LOGW(fmt,...) \ + do { \ + fprintf(stderr,"%s:%d: warning: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ + }while(0) +#define LOGI(fmt,...) \ + do { \ + fprintf(stderr,"%s:%d: info: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ + }while(0) +#else +#endif + +#define Printf printf + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif // MAX + +static inline void NoOperation() {} +typedef void (*Function)(); + +static inline void Shape_Print(char * str, int64_t * shape, uint32_t ndim) { + uint32_t idx; + char tmp[10]; + for (idx = 0; idx < ndim; idx++) { + if (idx != (ndim-1)) { + sprintf(tmp, "%dx", (int)shape[idx]); + } else { + sprintf(tmp, "%d", (int)shape[idx]); + } + strcat(str, tmp); + } +} + +static inline uint32_t Shape_CountNonZero(int64_t * shape){ + uint32_t ndim; + for (ndim = 0; ndim < TVM_CRT_MAX_NDIM; ndim++) { + if (shape[ndim] == 0) { + break; + } + } + return ndim; +} + +static inline uint32_t Shape_Accumulate(int64_t * shape){ + int64_t accum = 1; + uint32_t ndim; + for (ndim = 0; ndim < TVM_CRT_MAX_NDIM; ndim++) { + if (shape[ndim] == 0) { break; } + accum *= shape[ndim]; + } + return accum; +} + +//// seq class + +typedef struct seq_t { + uint32_t data[500]; + uint32_t size; + void (*push_back)(struct seq_t * seq, uint32_t src); + uint32_t * (*back)(struct seq_t * seq); + void (*pop_back)(struct seq_t * seq); +} Seq; + +static inline void SeqPush(Seq * seq, uint32_t src) { + if (seq->size >= 500) { + LOGE("seq too large."); + } + seq->data[seq->size] = src; + seq->size += 1; +} + +static inline uint32_t * SeqBack(Seq * seq) { + if (seq->size >= 500) { + LOGE("seq too large."); + } + return seq->data + (seq->size-1); +} + +static inline void SeqPop(Seq * seq) { + if (seq->size >= 500) { + Printf("seq size is too large.\n"); + } + if (seq->size == 0) { + Printf("seq size is too small.\n"); + } + seq->size -= 1; +} + +static inline Seq * SeqCreate() { + Seq * seq = (Seq*)malloc(sizeof(Seq)); + memset(seq, 0, sizeof(Seq)); + seq->push_back = SeqPush; + seq->back = SeqBack; + seq->pop_back = SeqPop; + return seq; +} + +#endif // COMMON_H_ diff --git a/src/runtime/crt/graph_runtime.h b/include/tvm/runtime/crt/graph_runtime.h similarity index 98% rename from src/runtime/crt/graph_runtime.h rename to include/tvm/runtime/crt/graph_runtime.h index 6e151b3d4e01..b49091f3917c 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/include/tvm/runtime/crt/graph_runtime.h @@ -24,12 +24,12 @@ #ifndef TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ #define TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ -#include -#include "ndarray.h" -#include "packed_func.h" -#include "module.h" -#include "io.h" -#include "load_json.h" +#include +#include +#include +#include +// #include "io.h" +#include /*! \brief macro to do C API call */ #define TVM_CCALL(func) \ diff --git a/src/runtime/crt/load_json.h b/include/tvm/runtime/crt/load_json.h similarity index 100% rename from src/runtime/crt/load_json.h rename to include/tvm/runtime/crt/load_json.h diff --git a/src/runtime/crt/module.h b/include/tvm/runtime/crt/module.h similarity index 95% rename from src/runtime/crt/module.h rename to include/tvm/runtime/crt/module.h index 324660a5faf8..5378cd951a43 100644 --- a/src/runtime/crt/module.h +++ b/include/tvm/runtime/crt/module.h @@ -25,8 +25,8 @@ #define TVM_RUNTIME_MODULE_H_ #include -#include "c_runtime_api.h" -#include "common.h" +#include +#include struct packed_func_t; typedef struct packed_func_t PackedFunc; diff --git a/src/runtime/crt/ndarray.h b/include/tvm/runtime/crt/ndarray.h similarity index 95% rename from src/runtime/crt/ndarray.h rename to include/tvm/runtime/crt/ndarray.h index d919d55f323c..9aae9f4b9314 100644 --- a/src/runtime/crt/ndarray.h +++ b/include/tvm/runtime/crt/ndarray.h @@ -18,16 +18,16 @@ */ /*! - * \file tvm/runtime/ndarray.h + * \file tvm/runtime/crt/ndarray.h * \brief Abstract device memory management API */ #ifndef TVM_RUNTIME_NDARRAY_H_ #define TVM_RUNTIME_NDARRAY_H_ -#include "c_runtime_api.h" -#include "c_backend_api.h" -#include "common.h" -#include "dlpack.h" +#include +#include +#include +#include /*! \brief Magic number for NDArray file */ static const uint64_t kTVMNDArrayMagic = 0xDD5E40F096B4A13F; diff --git a/include/tvm/runtime/crt/packed_func.h b/include/tvm/runtime/crt/packed_func.h new file mode 100644 index 000000000000..eff3a4cfd26b --- /dev/null +++ b/include/tvm/runtime/crt/packed_func.h @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \file tvm/runtime/packed_func.h + * \brief Type-erased function used across TVM API. + */ +#ifndef TVM_RUNTIME_PACKED_FUNC_H_ +#define TVM_RUNTIME_PACKED_FUNC_H_ + +// #ifndef _LIBCPP_SGX_NO_IOSTREAMS +// #include +// #endif +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +#include +#include +#include +// #include "node_base.h" + +// namespace HalideIR { +// // Forward declare type for extensions +// // The header works fine without depending on this. +// struct Type; +// struct Expr; +// } + +// Whether use TVM runtime in header only mode. +#ifndef TVM_RUNTIME_HEADER_ONLY +#define TVM_RUNTIME_HEADER_ONLY 0 +#endif + +static inline DLDataType String2DLDataType(const char * s) { + DLDataType t; + // handle None type + if (strlen(s) == 0) { + t.bits = 0; t.lanes = 0; t.code = kTVMOpaqueHandle; // kHandle; + return t; + } + t.bits = 32; t.lanes = 1; + const char* scan; + if (!strncmp(s, "int", 3)) { // s.substr(0, 3) == "int" + t.code = kDLInt; scan = s + 3; + } else if (!strncmp(s, "uint", 4)) { // s.substr(0, 4) == "uint" + t.code = kDLUInt; scan = s + 4; + } else if (!strncmp(s, "float", 5)) { // s.substr(0, 5) == "float" + t.code = kDLFloat; scan = s + 5; + } else if (!strncmp(s, "handle", 6)) { // s.substr(0, 6) == "handle" + t.code = kTVMOpaqueHandle; // kHandle; + t.bits = 64; // handle uses 64 bit by default. + scan = s + 6; + } else if (!strcmp(s, "bool")) { + t.code = kDLUInt; + t.bits = 1; + t.lanes = 1; + return t; + } else { + scan = s; + // LOG(FATAL) << "unknown type " << s; + LOGE("unknown type %s\n", s); + } + char* xdelim; // emulate sscanf("%ux%u", bits, lanes) + uint8_t bits = (uint8_t)(strtoul(scan, &xdelim, 10)); + if (bits != 0) t.bits = bits; + char* endpt = xdelim; + if (*xdelim == 'x') { + t.lanes = (uint16_t)(strtoul(xdelim + 1, &endpt, 10)); + } + if (!(endpt == s + strlen(s))){ + LOGE("unknown type %s\n", s); + } + return t; +} + +typedef struct tvm_args_t { + TVMValue values[TVM_CRT_MAX_ARGS]; + uint32_t tcodes[TVM_CRT_MAX_ARGS]; + uint32_t values_count; +} TVMArgs; + +static inline TVMArgs TVMArgs_Create(TVMValue * values, uint32_t * tcodes, uint32_t values_count) { + uint32_t idx; + TVMArgs args; + memset(&args, 0, sizeof(args)); + for (idx = 0; idx < values_count; idx++) { + memcpy(args.values + idx, values + idx, sizeof(TVMValue)); + args.tcodes[idx] = tcodes[idx]; + } + args.values_count = values_count; + return args; +} + +// static inline int TVMNoOperation(TVMValue * args, uint32_t * type_codes, int num_args, +// TVMRetValueHandle ret, void* resource_handle) { +// return TVM_STATUS_SUCCESS; +// } + +static inline int TVMNoOperation(void * args, void * type_codes, int num_args) { + return TVM_STATUS_SUCCESS; +} + +typedef struct packed_func_t { + // Function (*GetFunction)(); + char name[200]; + TVMPackedCFunc fexec; + TVMArgs args; + void (*Call)(struct packed_func_t * pf); + void (*SetArgs)(struct packed_func_t * pf, const struct tvm_args_t * args); +} PackedFunc; + +static inline void PackedFunc_Call(PackedFunc * pf) { + uint32_t idx; + char args[200] = {0,}; + for (idx = 0; idx < pf->args.values_count; idx++) { + char tmp[20]; + sprintf(tmp, "%s,", (pf->args.tcodes[idx]==kArrayHandle) ? "float *" : "unknown"); + strcat(args, tmp); + } + args[strlen(args)-1] = '\0'; +#if TVM_CRT_DEBUG + LOGI("calling %s(%s)", pf->name, args); +#endif // TVM_CRT_DEBUG + pf->fexec(pf->args.values, pf->args.tcodes, pf->args.values_count); +} + +static inline void PackedFunc_SetArgs(PackedFunc * pf, const TVMArgs * args) { + memcpy(&(pf->args), args, sizeof(TVMArgs)); +} + +PackedFunc fexecs[GRAPH_RUNTIME_MAX_NODES]; + +void PackedFunc_SetupExecs(); + +// Implement Module::GetFunction +// Put implementation in this file so we have seen the PackedFunc +static inline void Module_GetFunction(const char * name, PackedFunc * pf) { + int idx; + // PackedFunc pf; + memset(pf, 0, sizeof(PackedFunc)); + strcpy(pf->name, name); + pf->Call = PackedFunc_Call; + pf->SetArgs = PackedFunc_SetArgs; + pf->fexec = &TVMNoOperation; + for (idx = 0; idx < GRAPH_RUNTIME_MAX_NODES; idx++) { + if (!strcmp(fexecs[idx].name, name)) { + pf->fexec = fexecs[idx].fexec; +#if TVM_CRT_DEBUG + LOGI("setup function %s", name); +#endif // TVM_CRT_DEBUG + break; + } + } + if (idx==GRAPH_RUNTIME_MAX_NODES) { + LOGE("function handle for %s not found", name); + } + // return pf; +} + +#endif // TVM_RUNTIME_PACKED_FUNC_H_ From 75ef2c03d289a44b2a11e8f9474f5001fc03f213 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Tue, 11 Feb 2020 16:06:30 +0800 Subject: [PATCH 04/31] fix compatibility issues --- apps/bundle_deploy_c/Makefile | 14 +++++++++++++- include/tvm/runtime/crt/packed_func.h | 2 +- src/runtime/crt/graph_runtime.c | 14 +++++++------- src/runtime/crt/load_json.c | 2 +- src/runtime/crt/ndarray.c | 10 +++++----- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 5ad87395c2dd..165efa097f50 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -21,6 +21,12 @@ DEBUG = 0 MAX_NDIM = 6 MAX_ARGS = 10 +GRAPH_RUNTIME_NODE_MAX_INPUTS = 300 +GRAPH_RUNTIME_MAX_CONTEXTS = 1 +GRAPH_RUNTIME_MAX_NODES = 400 +GRAPH_RUNTIME_MAX_INPUT_NODES = 300 +GRAPH_RUNTIME_MAX_NODE_ROW_PTR = 300 +GRAPH_RUNTIME_MAX_OUTPUTS = 300 # Setup build environment TVM_ROOT=$(shell cd ../..; pwd) @@ -31,7 +37,13 @@ PKG_CFLAGS = -std=c99 -O2 -fPIC \ -I${TVM_ROOT}/3rdparty/dlpack/include \ -DTVM_CRT_DEBUG=${DEBUG} \ -DTVM_CRT_MAX_NDIM=${MAX_NDIM} \ - -DTVM_CRT_MAX_ARGS=${MAX_ARGS} + -DTVM_CRT_MAX_ARGS=${MAX_ARGS} \ + -DGRAPH_RUNTIME_NODE_MAX_INPUTS=${GRAPH_RUNTIME_NODE_MAX_INPUT} \ + -DGRAPH_RUNTIME_MAX_CONTEXTS=${GRAPH_RUNTIME_MAX_CONTEXTS} \ + -DGRAPH_RUNTIME_MAX_NODES=${GRAPH_RUNTIME_MAX_NODES} \ + -DGRAPH_RUNTIME_MAX_INPUT_NODES=${GRAPH_RUNTIME_MAX_INPUT_NODES} \ + -DGRAPH_RUNTIME_MAX_NODE_ROW_PTR=${GRAPH_RUNTIME_MAX_NODE_ROW_PTR} \ + -DGRAPH_RUNTIME_MAX_OUTPUTS=${GRAPH_RUNTIME_MAX_OUTPUTS} PKG_LDFLAGS = -pthread diff --git a/include/tvm/runtime/crt/packed_func.h b/include/tvm/runtime/crt/packed_func.h index eff3a4cfd26b..61ea61d28e65 100644 --- a/include/tvm/runtime/crt/packed_func.h +++ b/include/tvm/runtime/crt/packed_func.h @@ -136,7 +136,7 @@ static inline void PackedFunc_Call(PackedFunc * pf) { char args[200] = {0,}; for (idx = 0; idx < pf->args.values_count; idx++) { char tmp[20]; - sprintf(tmp, "%s,", (pf->args.tcodes[idx]==kArrayHandle) ? "float *" : "unknown"); + sprintf(tmp, "%s,", (pf->args.tcodes[idx]==kTVMNDArrayHandle) ? "float *" : "unknown"); strcat(args, tmp); } args[strlen(args)-1] = '\0'; diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index fb16f24887ed..36ce7a63d1ce 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -21,9 +21,9 @@ * \file graph_runtime.c * \brief implement graph runtime in pure C */ -#include "graph_runtime.h" -#include "c_api_common.h" -#include "load_param.h" +#include +//#include /*! * \brief Get the input index given the name of input. @@ -156,10 +156,10 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { uint32_t idx, dim; // Grab saved optimization plan from graph. - TVMType vtype[GRAPH_RUNTIME_MAX_NODES]; + DLDataType vtype[GRAPH_RUNTIME_MAX_NODES]; GraphRuntimeGraphAttr * attrs = &(runtime->attrs); for (idx = 0; idx < attrs->dltype_count; idx++) { - vtype[idx] = String2TVMType(attrs->dltype[idx]); + vtype[idx] = String2DLDataType(attrs->dltype[idx]); } // Size and device type of each storage pool entry. @@ -177,7 +177,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { size *= attrs->shape[idx][dim]; } } - TVMType t = vtype[idx]; + DLDataType t = vtype[idx]; uint32_t bits = t.bits * t.lanes; size_t bytes = ((bits + 7U) / 8U) * size; @@ -298,7 +298,7 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para v.v_handle = args[idx]; arg_ptr.arg_values[idx] = v; arg_ptr.arg_values_count ++; - arg_ptr.arg_tcodes[idx] = kArrayHandle; + arg_ptr.arg_tcodes[idx] = kTVMNDArrayHandle; arg_ptr.arg_tcodes_count ++; if (param->flatten_data) { arg_ptr.shape_data[idx] = Shape_Accumulate(t->shape); diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index bc58c9e35fe7..e6ebb90ee2c7 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -21,7 +21,7 @@ * \file saveload_json.cc * \brief Save and load graph to/from JSON file. */ -#include "load_json.h" +#include // the node entry structure in serialized format typedef struct _JSONNodeEntry { diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index 159ffe6d23d6..0aa63e21fc04 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -22,11 +22,11 @@ * \brief NDArray container infratructure. */ -#include "common.h" -#include "ndarray.h" -#include "c_runtime_api.h" -#include "c_backend_api.h" -#include "c_api_common.h" +#include +#include +#include +#include +//#include NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype) { uint32_t ndim = Shape_CountNonZero(shape); From e2f947590771302e0694500d414b9c110d697ec2 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Tue, 11 Feb 2020 17:30:52 +0800 Subject: [PATCH 05/31] fix compatibility issues --- apps/bundle_deploy_c/Makefile | 2 +- include/tvm/runtime/crt/graph_runtime.h | 2 +- include/tvm/runtime/crt/load_json.h | 7 ++++++- include/tvm/runtime/crt/vm.h | 1 + src/runtime/crt/graph_runtime.c | 7 ++++--- 5 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 include/tvm/runtime/crt/vm.h diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 165efa097f50..37ad3c0c2fad 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -38,7 +38,7 @@ PKG_CFLAGS = -std=c99 -O2 -fPIC \ -DTVM_CRT_DEBUG=${DEBUG} \ -DTVM_CRT_MAX_NDIM=${MAX_NDIM} \ -DTVM_CRT_MAX_ARGS=${MAX_ARGS} \ - -DGRAPH_RUNTIME_NODE_MAX_INPUTS=${GRAPH_RUNTIME_NODE_MAX_INPUT} \ + -DGRAPH_RUNTIME_NODE_MAX_INPUTS=${GRAPH_RUNTIME_NODE_MAX_INPUTS} \ -DGRAPH_RUNTIME_MAX_CONTEXTS=${GRAPH_RUNTIME_MAX_CONTEXTS} \ -DGRAPH_RUNTIME_MAX_NODES=${GRAPH_RUNTIME_MAX_NODES} \ -DGRAPH_RUNTIME_MAX_INPUT_NODES=${GRAPH_RUNTIME_MAX_INPUT_NODES} \ diff --git a/include/tvm/runtime/crt/graph_runtime.h b/include/tvm/runtime/crt/graph_runtime.h index b49091f3917c..6b000852b720 100644 --- a/include/tvm/runtime/crt/graph_runtime.h +++ b/include/tvm/runtime/crt/graph_runtime.h @@ -500,6 +500,6 @@ static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, uint32_t return runtime->node_row_ptr[nid] + index; } -int32_t TVMGraphRuntimeCreate(GraphRuntime * runtime, const char * sym_json, const Module * m, const TVMContext * ctxs); +GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, const TVMContext * ctxs); #endif // TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ diff --git a/include/tvm/runtime/crt/load_json.h b/include/tvm/runtime/crt/load_json.h index b88d2fa104de..1223e44c8ad4 100644 --- a/include/tvm/runtime/crt/load_json.h +++ b/include/tvm/runtime/crt/load_json.h @@ -46,7 +46,8 @@ enum { */ typedef struct json_reader_t { /*! \brief internal reader string */ - char is_[TVM_CRT_MAX_JSON_LENGTH]; + /* char is_[TVM_CRT_MAX_JSON_LENGTH]; */ + char * is_; char * isptr; /*! \brief "\\r" counter */ size_t line_count_r_; @@ -385,6 +386,10 @@ static inline JSONReader JSONReader_Create(const char * is) { reader.BeginObject = JSONReader_BeginObject; reader.NextArrayItem = JSONReader_NextArrayItem; reader.NextObjectItem = JSONReader_NextObjectItem; + // strcpy(reader.is_, is); + // TODO(liangfu): release memory + reader.is_ = (char*)malloc(strlen(is)+1); + memset(reader.is_, 0, strlen(is)+1); strcpy(reader.is_, is); reader.isptr = reader.is_; return reader; diff --git a/include/tvm/runtime/crt/vm.h b/include/tvm/runtime/crt/vm.h new file mode 100644 index 000000000000..853c72462dd1 --- /dev/null +++ b/include/tvm/runtime/crt/vm.h @@ -0,0 +1 @@ +/*! \brief Magic number for NDArray list file */ static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 36ce7a63d1ce..74a4effcf716 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -24,6 +24,7 @@ #include //#include +#include /*! * \brief Get the input index given the name of input. @@ -339,9 +340,9 @@ void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, runtime->SetupOpExecs(runtime); } -int32_t TVMGraphRuntimeCreate(GraphRuntime * runtime, const char * sym_json, +GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, const TVMContext * ctxs) { - // GraphRuntime runtime; // = (GraphRuntime*)malloc(sizeof(GraphRuntime)); + GraphRuntime * runtime = (GraphRuntime*)malloc(sizeof(GraphRuntime)); memset(runtime, 0, sizeof(GraphRuntime)); runtime->GetEntryId = GraphRuntime_GetEntryId; runtime->GetInputIndex = GraphRuntime_GetInputIndex; @@ -357,5 +358,5 @@ int32_t TVMGraphRuntimeCreate(GraphRuntime * runtime, const char * sym_json, runtime->module.GetFunction = Module_GetFunction; // init runtime->Init(runtime, sym_json, m, ctxs); - return TVM_STATUS_SUCCESS; // ModuleCreate(runtime); + return runtime; // TVM_STATUS_SUCCESS; // ModuleCreate(runtime); } From 3b5c0129bd8fd544e8a1d971fe65a5ed287bbb0e Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 12 Feb 2020 11:23:45 +0800 Subject: [PATCH 06/31] resolve most of the warnings and errros --- include/tvm/runtime/crt/load_json.h | 10 ++++----- include/tvm/runtime/crt/packed_func.h | 14 ++++++------- src/runtime/crt/ndarray.c | 30 +++++++++++++-------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/tvm/runtime/crt/load_json.h b/include/tvm/runtime/crt/load_json.h index 1223e44c8ad4..9a31cf33a7a1 100644 --- a/include/tvm/runtime/crt/load_json.h +++ b/include/tvm/runtime/crt/load_json.h @@ -57,7 +57,7 @@ typedef struct json_reader_t { * \brief record how many element processed in * current array/object scope. */ - Seq scope_counter_; + Seq * scope_counter_; char (*NextChar)(struct json_reader_t * reader); char (*NextNonSpace)(struct json_reader_t * reader); @@ -265,7 +265,7 @@ static inline void JSONReader_BeginObject(JSONReader * reader) { if (!(ch == '{')) { LOGE("Error at line X, Expect \'{\' but got \'%c\'", ch); } - Seq * scope_counter_ = &(reader->scope_counter_); + Seq * scope_counter_ = reader->scope_counter_; scope_counter_->push_back(scope_counter_, 0); } @@ -278,7 +278,7 @@ static inline void JSONReader_BeginObject(JSONReader * reader) { */ static inline bool JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { bool next = true; - Seq * scope_counter_ = &(reader->scope_counter_); + Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { int ch = reader->NextNonSpace(reader); if (ch == EOF) { @@ -327,7 +327,7 @@ static inline void JSONReader_BeginArray(JSONReader * reader) { if (ch != '[') { LOGE("Error at line X, Expect \'[\' but get \'%c\'", ch); } - Seq * scope_counter_ = &(reader->scope_counter_); + Seq * scope_counter_ = reader->scope_counter_; scope_counter_->push_back(scope_counter_, 0); } @@ -339,7 +339,7 @@ static inline void JSONReader_BeginArray(JSONReader * reader) { */ static inline bool JSONReader_NextArrayItem(JSONReader * reader) { bool next = true; - Seq * scope_counter_ = &(reader->scope_counter_); + Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { int ch = reader->NextNonSpace(reader); if (ch == EOF) { diff --git a/include/tvm/runtime/crt/packed_func.h b/include/tvm/runtime/crt/packed_func.h index 61ea61d28e65..51c970d66402 100644 --- a/include/tvm/runtime/crt/packed_func.h +++ b/include/tvm/runtime/crt/packed_func.h @@ -113,15 +113,15 @@ static inline TVMArgs TVMArgs_Create(TVMValue * values, uint32_t * tcodes, uint3 return args; } -// static inline int TVMNoOperation(TVMValue * args, uint32_t * type_codes, int num_args, -// TVMRetValueHandle ret, void* resource_handle) { -// return TVM_STATUS_SUCCESS; -// } - -static inline int TVMNoOperation(void * args, void * type_codes, int num_args) { +static inline int TVMNoOperation(TVMValue * args, int * type_codes, int num_args, + TVMRetValueHandle ret, void * res) { return TVM_STATUS_SUCCESS; } +// static inline int TVMNoOperation(void * args, int * type_codes, int num_args) { +// return TVM_STATUS_SUCCESS; +// } + typedef struct packed_func_t { // Function (*GetFunction)(); char name[200]; @@ -143,7 +143,7 @@ static inline void PackedFunc_Call(PackedFunc * pf) { #if TVM_CRT_DEBUG LOGI("calling %s(%s)", pf->name, args); #endif // TVM_CRT_DEBUG - pf->fexec(pf->args.values, pf->args.tcodes, pf->args.values_count); + pf->fexec(pf->args.values, pf->args.tcodes, pf->args.values_count, 0, 0); } static inline void PackedFunc_SetArgs(PackedFunc * pf, const TVMArgs * args) { diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index 0aa63e21fc04..da0557561de6 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -36,13 +36,13 @@ NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype) { } int TVMArrayAlloc(const tvm_index_t* shape, - uint8_t ndim, - uint8_t dtype_code, - uint8_t dtype_bits, - uint16_t dtype_lanes, - uint8_t device_type, - uint8_t device_id, - TVMArrayHandle out) { + int ndim, + int dtype_code, + int dtype_bits, + int dtype_lanes, + int device_type, + int device_id, + TVMArrayHandle * out) { API_BEGIN(); uint32_t idx = 0; DLDataType dtype; @@ -52,21 +52,21 @@ int TVMArrayAlloc(const tvm_index_t* shape, DLContext ctx; ctx.device_type = device_type; ctx.device_id = device_id; - out->ctx = ctx; - out->ndim = ndim; - out->dtype = dtype; + (*out)->ctx = ctx; + (*out)->ndim = ndim; + (*out)->dtype = dtype; uint32_t bytes = (dtype_bits + 7) / 8; uint32_t size = 1; for (idx = 0; idx < ndim; idx++) { size *= shape[idx]; } - out->data = TVMBackendAllocWorkspace(device_type, device_id, size, dtype_code, dtype_bits); - memset(out->data, 0, size * bytes); + (*out)->data = TVMBackendAllocWorkspace(device_type, device_id, size, dtype_code, dtype_bits); + memset((*out)->data, 0, size * bytes); for (idx = 0; idx < ndim; idx++) { - out->shape[idx] = shape[idx]; - out->strides = 0; + (*out)->shape[idx] = shape[idx]; + (*out)->strides = 0; } - out->byte_offset = 0; + (*out)->byte_offset = 0; API_END(); } From ad3aa5376d211dcdc98782d6dd9a6b38df99c9df Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 12 Feb 2020 12:21:18 +0800 Subject: [PATCH 07/31] implement c_backend_api --- apps/bundle_deploy_c/runtime.c | 1 + src/runtime/crt/c_backend_api.c | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/runtime/crt/c_backend_api.c diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index 12d172e2fab0..620189ada91d 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -39,6 +39,7 @@ /* #include "../../src/runtime/system_library.cc" */ /* #include "../../src/runtime/graph/graph_runtime.cc" */ +#include "../../src/runtime/crt/c_backend_api.c" #include "../../src/runtime/crt/graph_runtime.c" #include "../../src/runtime/crt/load_json.c" #include "../../src/runtime/crt/ndarray.c" diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c new file mode 100644 index 000000000000..17b07d83376c --- /dev/null +++ b/src/runtime/crt/c_backend_api.c @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + +#include +#include +#include + +void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t nbytes, int dtype_code_hint, + int dtype_bits_hint) { + void* ptr = nullptr; + assert(nbytes > 0); +#ifdef __ANDROID__ + ptr = memalign(64, nbytes); +#else + const int ret = posix_memalign(&ptr, 64, nbytes); + (void)ret; + assert(ret == 0); +#endif + return ptr; +} + +int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) { + free(ptr); + return 0; +} + +static char g_last_error[1024]; +void TVMAPISetLastError(const char* msg) { strcpy(g_last_error, msg); } +const char* TVMGetLastError(void) { return g_last_error; } + +int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_task) { + TVMParallelGroupEnv env; + env.num_task = 1; + flambda(0, &env, cdata); + return 0; +} + +int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { + printf("TVMBackendRegisterSystemLibSymbol not implemented.\n"); +} From 2d60116274be119a71714e13a11243dac62de036 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 12 Feb 2020 21:16:38 +0800 Subject: [PATCH 08/31] introduce bridge --- apps/bundle_deploy_c/Makefile | 17 +++++++--- apps/bundle_deploy_c/build_model.py | 50 +++++++++++++++++++++++------ apps/bundle_deploy_c/bundle.c | 1 + include/tvm/runtime/crt/ndarray.h | 1 + src/runtime/crt/c_api_common.h | 26 --------------- src/runtime/crt/c_backend_api.c | 2 +- src/runtime/crt/graph_runtime.c | 11 +++++-- 7 files changed, 64 insertions(+), 44 deletions(-) delete mode 100644 src/runtime/crt/c_api_common.h diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 37ad3c0c2fad..bbcde3587036 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -18,7 +18,7 @@ # Makefile Example to bundle TVM modules. # Configure runtime -DEBUG = 0 +DEBUG = 1 MAX_NDIM = 6 MAX_ARGS = 10 GRAPH_RUNTIME_NODE_MAX_INPUTS = 300 @@ -31,7 +31,11 @@ GRAPH_RUNTIME_MAX_OUTPUTS = 300 # Setup build environment TVM_ROOT=$(shell cd ../..; pwd) DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CFLAGS = -std=c99 -O2 -fPIC \ +PKG_CXXFLAGS = -std=c++14 -O0 -g -fPIC \ + -I${TVM_ROOT}/include \ + -I${DMLC_CORE}/include \ + -I${TVM_ROOT}/3rdparty/dlpack/include +PKG_CFLAGS = -std=c99 -O0 -g -fPIC \ -I${TVM_ROOT}/include \ -I${DMLC_CORE}/include \ -I${TVM_ROOT}/3rdparty/dlpack/include \ @@ -54,7 +58,7 @@ test: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/demo: demo.cc @mkdir -p $(@D) - gcc $(PKG_CFLAGS) -o $@ $^ -ldl + g++ $(PKG_CXXFLAGS) -o $@ $^ -ldl # Serialize our graph.json file. $(build_dir)/graph.json.c: $(build_dir)/graph.json @@ -64,14 +68,17 @@ $(build_dir)/graph.json.c: $(build_dir)/graph.json $(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ -$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin: build_model.py +$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/bridge.c: build_model.py python3 $< -o $(build_dir) # Build our bundle against the serialized bundle.cc API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.c $(build_dir)/params.bin.c +$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.c $(build_dir)/params.bin.c $(build_dir)/bridge.c @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) clean: + rm -r $(build_dir)/bundle.so + +cleanall: rm -r $(build_dir) diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index de9e73522ca2..213fe19bf55a 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -21,15 +21,9 @@ from tvm import relay import tvm import logging +import json - -def main(): - logging.basicConfig(level=logging.INFO) - - parser = argparse.ArgumentParser() - parser.add_argument('-o', '--out-dir', default='.') - opts = parser.parse_args() - +def build_module(opts): dshape = (1, 3, 224, 224) from mxnet.gluon.model_zoo.vision import get_model block = get_model('mobilenet0.25', pretrained=True) @@ -52,6 +46,44 @@ def main(): with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: f_params.write(relay.save_param_dict(params)) +def build_bridge(opts): + build_dir = os.path.abspath(opts.out_dir) + json_data = {} + with open(os.path.join(build_dir, 'graph.json'), 'rt') as fp: + json_data = json.loads(fp.read()) + if json_data == {}: + return + else: + nodes = [node['name'] for node in json_data['nodes'] if node['op'] == "tvm_op"] + with open(os.path.join(build_dir, 'bridge.c'), 'w') as f_bridge: + f_bridge.write("#include \n") + f_bridge.write("\n") + f_bridge.write("#define REGISTER_PACKED_FUNC(func_name) \\\n") + f_bridge.write(" do { \\\n") + f_bridge.write(" strcpy(fexecs[idx].name, #func_name ); \\\n") + f_bridge.write(" fexecs[idx].fexec = func_name ; \\\n") + f_bridge.write(" idx ++; \\\n") + f_bridge.write(" } while (false)\n") + f_bridge.write("\n") + for node in nodes: + if node[-2:] in [str(_) for _ in range(21, 25)]: + continue + f_bridge.write("int %s(TVMValue * args, int * arg_type_ids, int num_args, TVMRetValueHandle ret, void * res);\n" % (node,)) + f_bridge.write("\n") + f_bridge.write("void PackedFunc_SetupExecs() {\n") + f_bridge.write(" int32_t idx = 0;\n") + for node in nodes: + if node[-2:] in [str(_) for _ in range(21, 25)]: + continue + f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) + f_bridge.write("}\n") if __name__ == '__main__': - main() + logging.basicConfig(level=logging.INFO) + + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--out-dir', default='.') + opts = parser.parse_args() + + build_module(opts) + build_bridge(opts) diff --git a/apps/bundle_deploy_c/bundle.c b/apps/bundle_deploy_c/bundle.c index 33f86645c59b..78944d7d652e 100644 --- a/apps/bundle_deploy_c/bundle.c +++ b/apps/bundle_deploy_c/bundle.c @@ -32,6 +32,7 @@ extern unsigned int build_params_bin_len; /* extern "C" { */ TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { + printf("tvm_runtime_create\n"); char * json_data = build_graph_json; /* memset(json_data, 0, build_graph_json_len + 1); */ /* memcpy(json_data, build_graph_json, build_graph_json_len); */ diff --git a/include/tvm/runtime/crt/ndarray.h b/include/tvm/runtime/crt/ndarray.h index 9aae9f4b9314..ef12cf15dafb 100644 --- a/include/tvm/runtime/crt/ndarray.h +++ b/include/tvm/runtime/crt/ndarray.h @@ -42,6 +42,7 @@ static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, DLDataType NDArray ret; memset(&ret, 0, sizeof(NDArray)); ret.dl_tensor.ndim = ndim; + ret.dl_tensor.shape = (int64_t*)malloc(sizeof(int64_t)*ndim); // TODO(liangfu): release memory memcpy(ret.dl_tensor.shape, shape, sizeof(int64_t)*ndim); ret.dl_tensor.dtype = dtype; ret.dl_tensor.ctx = ctx; diff --git a/src/runtime/crt/c_api_common.h b/src/runtime/crt/c_api_common.h deleted file mode 100644 index b4d3d9489539..000000000000 --- a/src/runtime/crt/c_api_common.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/*! - * \file c_api_common.h - * \brief Common fields of all C APIs - */ - -#define API_BEGIN() int status; do { status = TVM_STATUS_SUCCESS; } while(false) -#define API_END() return status diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c index 17b07d83376c..26433a7e4c11 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/c_backend_api.c @@ -54,5 +54,5 @@ int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_ta } int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { - printf("TVMBackendRegisterSystemLibSymbol not implemented.\n"); + printf("TVMBackendRegisterSystemLibSymbol(%s) not implemented.\n", name); } diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 74a4effcf716..6ebaea7e7418 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -258,9 +258,9 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { #if TVM_CRT_DEBUG /* (runtime->op_execs[1].args.values[0].v_handle)->ndim = 3; */ LOGI("DEBUG: (runtime->op_execs[1].args.values[0].v_handle)->ndim=%d", - (runtime->op_execs[1].args.values[0].v_handle)->ndim); + ((DLTensor*)(runtime->op_execs[1].args.values[0].v_handle))->ndim); LOGI("DEBUG: (runtime->op_execs[%d].args.values[0].v_handle)->ndim=%d", - nid, (runtime->op_execs[nid].args.values[0].v_handle)->ndim); + nid, ((DLTensor*)(runtime->op_execs[nid].args.values[0].v_handle))->ndim); #endif // TVM_CRT_DEBUG } } @@ -315,7 +315,7 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para TVMArgs targs = TVMArgs_Create(arg_ptr.arg_values, arg_ptr.arg_tcodes, arg_ptr.arg_values_count); #if TVM_CRT_DEBUG LOGI("set args for %s function: dims=%d,%d", param->func_name, - (targs.values[0].v_handle)->ndim, (targs.values[1].v_handle)->ndim); + ((DLTensor*)(targs.values[0].v_handle))->ndim, ((DLTensor*)(targs.values[1].v_handle))->ndim); #endif // TVM_CRT_DEBUG pf->SetArgs(pf, &targs); @@ -332,11 +332,16 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para */ void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, const Module * module, const TVMContext * ctxs) { + printf("GraphRuntime_Init()\n"); JSONReader reader = JSONReader_Create(graph_json); + printf("GraphRuntime_Load()\n"); runtime->Load(runtime, &reader); runtime->ctxs[0] = ctxs[0]; + printf("GraphRuntime_SetupStorage()\n"); runtime->SetupStorage(runtime); + printf("PackedFunc_SetupExecs()\n"); PackedFunc_SetupExecs(); + printf("GraphRuntime_SetupOpExecs()\n"); runtime->SetupOpExecs(runtime); } From 200842d75a2e85905fb6ccf5a9f940425eeac8e8 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Sat, 15 Feb 2020 16:49:45 +0800 Subject: [PATCH 09/31] working well --- apps/bundle_deploy_c/Makefile | 14 ++- apps/bundle_deploy_c/build_model.py | 10 +- apps/bundle_deploy_c/bundle.c | 31 ++--- apps/bundle_deploy_c/demo.c | 150 ------------------------ apps/bundle_deploy_c/demo.cc | 91 ++++++++++++++ include/tvm/runtime/crt/common.h | 10 +- include/tvm/runtime/crt/graph_runtime.h | 3 +- include/tvm/runtime/crt/ndarray.h | 5 +- include/tvm/runtime/crt/packed_func.h | 14 --- src/runtime/crt/c_backend_api.c | 7 +- src/runtime/crt/graph_runtime.c | 51 ++++---- 11 files changed, 155 insertions(+), 231 deletions(-) delete mode 100644 apps/bundle_deploy_c/demo.c create mode 100644 apps/bundle_deploy_c/demo.cc diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index bbcde3587036..265890b2b46b 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -18,7 +18,7 @@ # Makefile Example to bundle TVM modules. # Configure runtime -DEBUG = 1 +DEBUG = 0 MAX_NDIM = 6 MAX_ARGS = 10 GRAPH_RUNTIME_NODE_MAX_INPUTS = 300 @@ -73,12 +73,18 @@ $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir # Build our bundle against the serialized bundle.cc API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.c $(build_dir)/params.bin.c $(build_dir)/bridge.c +$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.o $(build_dir)/params.bin.o $(build_dir)/bridge.c @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) +$(build_dir)/graph.json.o: $(build_dir)/graph.json.c + gcc -c ${PKG_CFLAGS} -o $@ $^ + +$(build_dir)/params.bin.o: $(build_dir)/params.bin.c + gcc -c ${PKG_CFLAGS} -o $@ $^ + clean: - rm -r $(build_dir)/bundle.so + rm -rf $(build_dir)/bundle.so cleanall: - rm -r $(build_dir) + rm -rf $(build_dir) diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index 213fe19bf55a..7b8470a20468 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -54,7 +54,7 @@ def build_bridge(opts): if json_data == {}: return else: - nodes = [node['name'] for node in json_data['nodes'] if node['op'] == "tvm_op"] + nodes = [node['attrs']['func_name'] for node in json_data['nodes'] if node['op'] == "tvm_op"] with open(os.path.join(build_dir, 'bridge.c'), 'w') as f_bridge: f_bridge.write("#include \n") f_bridge.write("\n") @@ -66,15 +66,15 @@ def build_bridge(opts): f_bridge.write(" } while (false)\n") f_bridge.write("\n") for node in nodes: - if node[-2:] in [str(_) for _ in range(21, 25)]: - continue + # if node[-2:] in [str(_) for _ in range(21, 25)]: + # continue f_bridge.write("int %s(TVMValue * args, int * arg_type_ids, int num_args, TVMRetValueHandle ret, void * res);\n" % (node,)) f_bridge.write("\n") f_bridge.write("void PackedFunc_SetupExecs() {\n") f_bridge.write(" int32_t idx = 0;\n") for node in nodes: - if node[-2:] in [str(_) for _ in range(21, 25)]: - continue + # if node[-2:] in [str(_) for _ in range(21, 25)]: + # continue f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) f_bridge.write("}\n") diff --git a/apps/bundle_deploy_c/bundle.c b/apps/bundle_deploy_c/bundle.c index 78944d7d652e..dee8b1f39e48 100644 --- a/apps/bundle_deploy_c/bundle.c +++ b/apps/bundle_deploy_c/bundle.c @@ -29,19 +29,12 @@ extern unsigned int build_params_bin_len; #define TVM_BUNDLE_FUNCTION __attribute__((visibility("default"))) -/* extern "C" { */ - TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { - printf("tvm_runtime_create\n"); char * json_data = build_graph_json; - /* memset(json_data, 0, build_graph_json_len + 1); */ - /* memcpy(json_data, build_graph_json, build_graph_json_len); */ - + int device_type = kDLCPU; int device_id = 0; - /* tvm::runtime::Module mod = */ - /* (*tvm::runtime::Registry::Get("tvm.graph_runtime.create"))( */ - /* json_data, mod_syslib, device_type, device_id); */ + TVMByteArray params; params.data = build_params_bin; params.size = build_params_bin_len; @@ -51,30 +44,26 @@ TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { ctx.device_id = device_id; GraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); - /* mod.GetFunction("load_params")(params); */ runtime->LoadParams(runtime, params.data, params.size); - - /* return new tvm::runtime::Module(mod); */ + return runtime; } TVM_BUNDLE_FUNCTION void tvm_runtime_destroy(GraphRuntime * runtime) { - /* delete reinterpret_cast(handle); */ + TVMGraphRuntimeRelease(&runtime); } TVM_BUNDLE_FUNCTION void tvm_runtime_set_input(GraphRuntime * runtime, const char * name, - void * tensor) { - /* reinterpret_cast(handle)->GetFunction("set_input")( */ - /* name, reinterpret_cast(tensor)); */ + DLTensor * tensor) { + runtime->SetInput(runtime, "data", tensor); } TVM_BUNDLE_FUNCTION void tvm_runtime_run(GraphRuntime * runtime) { - /* reinterpret_cast(handle)->GetFunction("run")(); */ + runtime->Run(runtime); } TVM_BUNDLE_FUNCTION void tvm_runtime_get_output(GraphRuntime * runtime, int32_t index, - void * tensor) { - /* reinterpret_cast(handle)->GetFunction("get_output")( */ - /* index, reinterpret_cast(tensor)); */ + DLTensor * tensor) { + runtime->GetOutput(runtime, index, tensor); } -/* } */ + diff --git a/apps/bundle_deploy_c/demo.c b/apps/bundle_deploy_c/demo.c deleted file mode 100644 index 06e959e6a170..000000000000 --- a/apps/bundle_deploy_c/demo.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 "tvm/runtime/c_runtime_api.h" -#include -#include //dlopen -#include - -int main(int argc, char **argv) { - /* assert(argc == 2 && "Usage: demo "); */ - /* auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); */ - /* assert(bundle); */ - - // json graph - const char * json_fn = "build/deploy.min.json"; - const char * params_fn = "build/deploy.params"; - - FILE * json_in = fopen(json_fn, "rt"); - /* std::string json_data((std::istreambuf_iterator(json_in)), std::istreambuf_iterator()); */ - /* json_in.close(); */ - EXPECT_NE(json_in, (void*)0); - if (json_in == (void*)0) { exit(-1); } - size_t json_size = findSize(json_fn); - char * json_data = (char*)malloc(json_size+1); - fread(json_data, json_size, 1, json_in); - fclose(json_in); - json_in = 0; - - // parameters in binary - FILE * params_in = fopen(params_fn, "rb"); - EXPECT_NE(params_in, (void*)0); - if (params_in == (void*)0) { exit(-1); } - /* std::string params_data((std::istreambuf_iterator(params_in)), std::istreambuf_iterator()); */ - /* params_in.close(); */ - size_t params_size = findSize(params_fn); - char * params_data = (char*)malloc(params_size); - fread(params_data, params_size, 1, params_in); - fclose(params_in); - params_in = 0; - - // parameters need to be TVMByteArray type to indicate the binary data - TVMByteArray params_arr; - params_arr.data = params_data; - params_arr.size = params_size; - - int dtype_code = kDLFloat; - int dtype_bits = 32; - int dtype_lanes = 1; - int device_type = kDLCPU; - int device_id = 0; - - // get global function module for graph runtime - TVMContext ctx; - ctx.device_type = kDLCPU; - ctx.device_id = 0; - { - JSONReader reader; - EXPECT_GE(sizeof(reader.is_), json_size); - } - GraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); - /* typedef Module * (*TVMGraphRuntimeCreateFunc)(char *, void *, int, int) ; */ - /* TVMFunctionHandle graph_runtime; */ - /* TVMGraphRuntimeCreateFunc graph_runtime; */ - /* TVMFuncGetGlobal("tvm.graph_runtime.create", (TVMFunctionHandle*)&graph_runtime); */ - /* Module * mod = graph_runtime(json_data, mod_syslib, device_type, device_id); */ - /* Module * mod = graph_runtime->pushArg(json_data)->pushArg(mod_syslib) */ - /* ->pushArg(device_type)->pushArg(device_id)->invoke()->asModule(); */ - - DLTensor x; - int in_ndim = 4; - int64_t in_shape[4] = {1, 3, 224, 224}; - TVMArrayAlloc(in_shape, in_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &x); - - // load image data saved in binary - FILE * data_fin = fopen("cat.bin", "rb"); - /* data_fin.read(static_cast(x->data), 3 * 224 * 224 * 4); */ - int64_t data_size = findSize("cat.bin"); - /* char * data_data = (char*)malloc(data_size); */ - if (data_size != (in_shape[0]*in_shape[1]*in_shape[2]*in_shape[3]*4)) { - LOGE("wrong file size: %d != %d", (int32_t)data_size, (int32_t)(in_shape[0]*in_shape[1]*in_shape[2]*in_shape[3]*4)); - } - fread(x.data, data_size, 1, data_fin); - fclose(data_fin); - data_fin = 0; - - // get the function from the module(set input data) - // TVMSetInputCFunc set_input = mod->GetFunction("set_input"); - // mod->set_input(mod, "data", &x); - runtime->SetInput(runtime, "data", &x); - - // get the function from the module(load patameters) - // TVMLoadParamsCFunc load_params = mod->GetFunction("load_params"); - runtime->LoadParams(runtime, params_arr.data, params_arr.size); - - // get the function from the module(run it) - // TVMRunCFunc run = mod->GetFunction("run"); - runtime->Run(runtime); - -// for (int idx = 0; idx < 1000; idx++) { -// LOGI("%d: %.3f", idx, ((float*)runtime->op_execs[263].args.values[1].v_handle->data)[idx]); -// } - - DLTensor y; - int out_ndim = 1; - int64_t out_shape[1] = {1000, }; - TVMArrayAlloc(out_shape, out_ndim, dtype_code, dtype_bits, dtype_lanes, device_type, device_id, &y); - - // get the function from the module(get output data) - // TVMPackedCFunc get_output = mod->GetFunction("get_output"); - /* get_output(0, y); */ - runtime->GetOutput(runtime, 0, &y); - - // get the maximum position in output vector - // auto y_iter = static_cast(y->data); - // auto max_iter = std::max_element(y_iter, y_iter + 1000); - // auto max_index = std::distance(y_iter, max_iter); - float max_iter = - FLT_MAX; - int32_t max_index = -1; - float * y_iter = (float*)y.data; - // qsort(y_iter, 1000, sizeof(float), compareFloat); - for (int32_t idx = 0; idx < 1000; idx++) { - if (y_iter[idx] > max_iter) { - max_iter = y_iter[idx]; - max_index = idx; - } - } - - LOGI("The maximum position in output vector is: %d, with max-value %f.", max_index, max_iter); - - TVMArrayFree(&y); - TVMArrayFree(&x); - - return 0; -} diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc new file mode 100644 index 000000000000..17e8f4edb42a --- /dev/null +++ b/apps/bundle_deploy_c/demo.cc @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "tvm/runtime/c_runtime_api.h" +#include +#include //dlopen +#include +#include +#include +#include + +template auto getFunc(void *bundle, const char *name) { + dlerror(); + auto *f = + reinterpret_cast::type>(dlsym(bundle, name)); + assert(!dlerror()); + return f; +} + +int main(int argc, char **argv) { + assert(argc == 2 && "Usage: demo "); + auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); + assert(bundle); + + auto *handle = getFunc(bundle, "tvm_runtime_create")(); + + std::vector input_storage(1 * 3 * 224 * 224); + std::mt19937 gen(0); + for (auto &e : input_storage) { + e = std::uniform_real_distribution(0.0, 1.0)(gen); + } + + std::vector input_shape = {1, 3, 224, 224}; + DLTensor input; + input.data = input_storage.data(); + input.ctx = DLContext{kDLCPU, 0}; + input.ndim = 4; + input.dtype = DLDataType{kDLFloat, 32, 1}; + input.shape = input_shape.data(); + input.strides = nullptr; + input.byte_offset = 0; + getFunc(bundle, "tvm_runtime_set_input")( + handle, "data", &input); + + auto *ftvm_runtime_run = + (auto (*)(void *)->void)dlsym(bundle, "tvm_runtime_run"); + assert(!dlerror()); + ftvm_runtime_run(handle); + + float output_storage[1000]; + std::vector output_shape = {1, 1000}; + DLTensor output; + output.data = output_storage; + output.ctx = DLContext{kDLCPU, 0}; + output.ndim = 2; + output.dtype = DLDataType{kDLFloat, 32, 1}; + output.shape = output_shape.data(); + output.strides = nullptr; + output.byte_offset = 0; + + getFunc(bundle, "tvm_runtime_get_output")( + handle, 0, &output); + float max_iter = -std::numeric_limits::max(); + int32_t max_index = -1; + for (auto i = 0; i < 1000; ++i) { + if (output_storage[i] > max_iter) { + max_iter = output_storage[i]; + max_index = i; + } + } + printf("The maximum position in output vector is: %d, with max-value %f.\n", max_index, max_iter); + getFunc(bundle, "tvm_runtime_destroy")(handle); + dlclose(bundle); + return 0; +} diff --git a/include/tvm/runtime/crt/common.h b/include/tvm/runtime/crt/common.h index 7e63632ec539..42952eb31a7f 100644 --- a/include/tvm/runtime/crt/common.h +++ b/include/tvm/runtime/crt/common.h @@ -112,12 +112,12 @@ static inline uint32_t Shape_CountNonZero(int64_t * shape){ return ndim; } -static inline uint32_t Shape_Accumulate(int64_t * shape){ +static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim){ int64_t accum = 1; - uint32_t ndim; - for (ndim = 0; ndim < TVM_CRT_MAX_NDIM; ndim++) { - if (shape[ndim] == 0) { break; } - accum *= shape[ndim]; + uint32_t idx; + for (idx = 0; idx < ndim; idx++) { + if (shape[idx] == 0) { break; } + accum *= shape[idx]; } return accum; } diff --git a/include/tvm/runtime/crt/graph_runtime.h b/include/tvm/runtime/crt/graph_runtime.h index 6b000852b720..a2440d03d622 100644 --- a/include/tvm/runtime/crt/graph_runtime.h +++ b/include/tvm/runtime/crt/graph_runtime.h @@ -299,7 +299,6 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR reader->ReadString(reader, type); if (!strcmp(type, "list_int")) { if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } - // std::vector temp; uint32_t temp[GRAPH_RUNTIME_MAX_NODES]; uint32_t temp_count = 0; reader->BeginArray(reader); @@ -502,4 +501,6 @@ static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, uint32_t GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, const TVMContext * ctxs); +void TVMGraphRuntimeRelease(GraphRuntime ** runtime); + #endif // TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ diff --git a/include/tvm/runtime/crt/ndarray.h b/include/tvm/runtime/crt/ndarray.h index ef12cf15dafb..07e95e7b395e 100644 --- a/include/tvm/runtime/crt/ndarray.h +++ b/include/tvm/runtime/crt/ndarray.h @@ -64,7 +64,7 @@ static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType d } static inline int NDArray_Load(NDArray * ret, const char ** strm) { - API_BEGIN(); + int32_t status = TVM_STATUS_SUCCESS; uint64_t header, reserved; header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); if (header != kTVMNDArrayMagic) { @@ -108,7 +108,8 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { } memcpy(ret->dl_tensor.data, *strm, data_byte_size); *strm += data_byte_size; - API_END(); + + return status; } #endif // TVM_RUNTIME_NDARRAY_H_ diff --git a/include/tvm/runtime/crt/packed_func.h b/include/tvm/runtime/crt/packed_func.h index 51c970d66402..1e8691f05628 100644 --- a/include/tvm/runtime/crt/packed_func.h +++ b/include/tvm/runtime/crt/packed_func.h @@ -132,17 +132,6 @@ typedef struct packed_func_t { } PackedFunc; static inline void PackedFunc_Call(PackedFunc * pf) { - uint32_t idx; - char args[200] = {0,}; - for (idx = 0; idx < pf->args.values_count; idx++) { - char tmp[20]; - sprintf(tmp, "%s,", (pf->args.tcodes[idx]==kTVMNDArrayHandle) ? "float *" : "unknown"); - strcat(args, tmp); - } - args[strlen(args)-1] = '\0'; -#if TVM_CRT_DEBUG - LOGI("calling %s(%s)", pf->name, args); -#endif // TVM_CRT_DEBUG pf->fexec(pf->args.values, pf->args.tcodes, pf->args.values_count, 0, 0); } @@ -167,9 +156,6 @@ static inline void Module_GetFunction(const char * name, PackedFunc * pf) { for (idx = 0; idx < GRAPH_RUNTIME_MAX_NODES; idx++) { if (!strcmp(fexecs[idx].name, name)) { pf->fexec = fexecs[idx].fexec; -#if TVM_CRT_DEBUG - LOGI("setup function %s", name); -#endif // TVM_CRT_DEBUG break; } } diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c index 26433a7e4c11..1a9f9508736d 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/c_backend_api.c @@ -27,10 +27,11 @@ void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t nbytes, int dtype_bits_hint) { void* ptr = nullptr; assert(nbytes > 0); + unsigned int dtype_bytes = dtype_bits_hint / 8; #ifdef __ANDROID__ - ptr = memalign(64, nbytes); + ptr = memalign(64, nbytes * dtype_bytes); #else - const int ret = posix_memalign(&ptr, 64, nbytes); + const int ret = posix_memalign(&ptr, 64, nbytes * dtype_bytes); (void)ret; assert(ret == 0); #endif @@ -54,5 +55,5 @@ int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_ta } int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { - printf("TVMBackendRegisterSystemLibSymbol(%s) not implemented.\n", name); + // printf("TVMBackendRegisterSystemLibSymbol(%s) not implemented.\n", name); } diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 6ebaea7e7418..189e4b6deaff 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -22,8 +22,6 @@ * \brief implement graph runtime in pure C */ #include -//#include #include /*! @@ -113,7 +111,7 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param status = TVM_STATUS_FAILURE; } - NDArray_Load(&(runtime->data_entry[eid]), &bptr); + status |= NDArray_Load(&(runtime->data_entry[eid]), &bptr); #if TVM_CRT_DEBUG char shape_desc[20]; memset(shape_desc, 0, sizeof(shape_desc)); @@ -149,7 +147,15 @@ int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * uint32_t nid = runtime->outputs[idx].node_id; uint32_t index = runtime->outputs[idx].index; uint32_t eid = runtime->GetEntryId(runtime, nid, index); - *out = runtime->data_entry[eid].dl_tensor; + + // copy data section to allocated output tensor + int32_t elem_bytes = out->dtype.bits / 8; + int64_t size = Shape_Accumulate(out->shape, out->ndim); + DLTensor * tensor = &(runtime->data_entry[eid].dl_tensor); + assert(out->ndim == tensor->ndim); + assert(out->dtype.bits == tensor->dtype.bits); + assert(Shape_Accumulate(out->shape, out->ndim) == Shape_Accumulate(tensor->shape, tensor->ndim)); + memcpy(out->data, tensor->data, size * elem_bytes); return status; } @@ -197,8 +203,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { TVMContext ctx = runtime->ctxs[0]; DLDataType dtype = {kDLFloat, 32, 1}; shape[0] = (pit.size + 3) / 4; - uint32_t ndim = Shape_CountNonZero(shape); - runtime->storage_pool[runtime->storage_pool_count] = NDArray_Empty(ndim, shape, dtype, ctx); + runtime->storage_pool[runtime->storage_pool_count] = NDArray_Empty(1, shape, dtype, ctx); if (runtime->storage_pool[runtime->storage_pool_count].dl_tensor.data == 0) { LOGE("fail to create storage_pool with idx=%d", idx); } @@ -210,8 +215,8 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { // is mapped to this pool. runtime->data_entry_count = runtime->node_row_ptr[runtime->node_row_ptr_count - 1]; for (idx = 0; idx < runtime->data_entry_count; ++idx) { - int storage_id = attrs->storage_id[idx]; - /* CHECK_LT(static_cast(storage_id), storage_pool_.size()); */ + size_t storage_id = attrs->storage_id[idx]; + assert(storage_id < runtime->storage_pool_count); runtime->data_entry[idx] = NDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], vtype[idx]); if (runtime->data_entry[idx].dl_tensor.data == 0) { @@ -255,13 +260,6 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { PackedFunc pf; runtime->CreateTVMOp(runtime, &(inode->param), args, args_count, inode->inputs_count, &pf); runtime->op_execs[nid] = pf; -#if TVM_CRT_DEBUG - /* (runtime->op_execs[1].args.values[0].v_handle)->ndim = 3; */ - LOGI("DEBUG: (runtime->op_execs[1].args.values[0].v_handle)->ndim=%d", - ((DLTensor*)(runtime->op_execs[1].args.values[0].v_handle))->ndim); - LOGI("DEBUG: (runtime->op_execs[%d].args.values[0].v_handle)->ndim=%d", - nid, ((DLTensor*)(runtime->op_execs[nid].args.values[0].v_handle))->ndim); -#endif // TVM_CRT_DEBUG } } API_END(); @@ -302,7 +300,7 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para arg_ptr.arg_tcodes[idx] = kTVMNDArrayHandle; arg_ptr.arg_tcodes_count ++; if (param->flatten_data) { - arg_ptr.shape_data[idx] = Shape_Accumulate(t->shape); + arg_ptr.shape_data[idx] = Shape_Accumulate(t->shape, t->ndim); t->ndim = 1; t->shape[0] = arg_ptr.shape_data[idx]; } @@ -313,10 +311,6 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para runtime->module.GetFunction(param->func_name, pf); TVMArgs targs = TVMArgs_Create(arg_ptr.arg_values, arg_ptr.arg_tcodes, arg_ptr.arg_values_count); -#if TVM_CRT_DEBUG - LOGI("set args for %s function: dims=%d,%d", param->func_name, - ((DLTensor*)(targs.values[0].v_handle))->ndim, ((DLTensor*)(targs.values[1].v_handle))->ndim); -#endif // TVM_CRT_DEBUG pf->SetArgs(pf, &targs); return TVM_STATUS_SUCCESS; @@ -332,16 +326,11 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para */ void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, const Module * module, const TVMContext * ctxs) { - printf("GraphRuntime_Init()\n"); JSONReader reader = JSONReader_Create(graph_json); - printf("GraphRuntime_Load()\n"); runtime->Load(runtime, &reader); runtime->ctxs[0] = ctxs[0]; - printf("GraphRuntime_SetupStorage()\n"); runtime->SetupStorage(runtime); - printf("PackedFunc_SetupExecs()\n"); PackedFunc_SetupExecs(); - printf("GraphRuntime_SetupOpExecs()\n"); runtime->SetupOpExecs(runtime); } @@ -363,5 +352,15 @@ GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, runtime->module.GetFunction = Module_GetFunction; // init runtime->Init(runtime, sym_json, m, ctxs); - return runtime; // TVM_STATUS_SUCCESS; // ModuleCreate(runtime); + return runtime; +} + +void TVMGraphRuntimeRelease(GraphRuntime ** pptr) { + int32_t idx; + GraphRuntime * runtime = *pptr; + for (idx = 0; idx < runtime->storage_pool_count; ++idx) { + free(runtime->storage_pool[idx].dl_tensor.data); + free(runtime->storage_pool[idx].dl_tensor.shape); + } + free(*pptr); } From 8d5a4099c458906ad6c5696bee077f53e32e7002 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Sat, 15 Feb 2020 23:11:46 +0800 Subject: [PATCH 10/31] move to header files and bundle.c into src/runtime/crt --- apps/bundle_deploy_c/Makefile | 4 +- apps/bundle_deploy_c/build_model.py | 4 +- apps/bundle_deploy_c/demo.cc | 2 +- apps/bundle_deploy_c/runtime.c | 11 +- include/tvm/runtime/crt/common.h | 169 ---------------- include/tvm/runtime/crt/vm.h | 28 +++ .../runtime/crt}/bundle.c | 5 +- src/runtime/crt/c_backend_api.c | 2 +- src/runtime/crt/graph_runtime.c | 96 +++++---- .../tvm => src}/runtime/crt/graph_runtime.h | 190 ++++++++++-------- src/runtime/crt/load_json.c | 12 +- {include/tvm => src}/runtime/crt/load_json.h | 136 +++++++++---- {include/tvm => src}/runtime/crt/module.h | 1 - src/runtime/crt/ndarray.c | 50 +---- {include/tvm => src}/runtime/crt/ndarray.h | 28 +-- .../tvm => src}/runtime/crt/packed_func.h | 57 ++---- 16 files changed, 330 insertions(+), 465 deletions(-) delete mode 100644 include/tvm/runtime/crt/common.h rename {apps/bundle_deploy_c => src/runtime/crt}/bundle.c (93%) rename {include/tvm => src}/runtime/crt/graph_runtime.h (74%) rename {include/tvm => src}/runtime/crt/load_json.h (78%) rename {include/tvm => src}/runtime/crt/module.h (98%) rename {include/tvm => src}/runtime/crt/ndarray.h (84%) rename {include/tvm => src}/runtime/crt/packed_func.h (72%) diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 265890b2b46b..abdad38ae84b 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -71,9 +71,9 @@ $(build_dir)/params.bin.c: $(build_dir)/params.bin $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/bridge.c: build_model.py python3 $< -o $(build_dir) -# Build our bundle against the serialized bundle.cc API, the runtime.cc API, and +# Build our bundle against the serialized bundle.c API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o $(build_dir)/graph.json.o $(build_dir)/params.bin.o $(build_dir)/bridge.c +$(build_dir)/bundle.so: runtime.c $(build_dir)/model.o $(build_dir)/graph.json.o $(build_dir)/params.bin.o $(build_dir)/bridge.c @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index 7b8470a20468..54db5d67afea 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -56,14 +56,14 @@ def build_bridge(opts): else: nodes = [node['attrs']['func_name'] for node in json_data['nodes'] if node['op'] == "tvm_op"] with open(os.path.join(build_dir, 'bridge.c'), 'w') as f_bridge: - f_bridge.write("#include \n") + f_bridge.write("#include \"../../../src/runtime/crt/packed_func.h\"\n") f_bridge.write("\n") f_bridge.write("#define REGISTER_PACKED_FUNC(func_name) \\\n") f_bridge.write(" do { \\\n") f_bridge.write(" strcpy(fexecs[idx].name, #func_name ); \\\n") f_bridge.write(" fexecs[idx].fexec = func_name ; \\\n") f_bridge.write(" idx ++; \\\n") - f_bridge.write(" } while (false)\n") + f_bridge.write(" } while (0)\n") f_bridge.write("\n") for node in nodes: # if node[-2:] in [str(_) for _ in range(21, 25)]: diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc index 17e8f4edb42a..fb8a2a2723ab 100644 --- a/apps/bundle_deploy_c/demo.cc +++ b/apps/bundle_deploy_c/demo.cc @@ -17,7 +17,7 @@ * under the License. */ -#include "tvm/runtime/c_runtime_api.h" +#include #include #include //dlopen #include diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index 620189ada91d..f31c5a6058db 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -18,12 +18,14 @@ */ #include -#include +#include +#include +/* #include */ /* #include */ /* #include */ -#include -#include -#include +/* #include */ +/* #include */ +/* #include */ /* #include "../../src/runtime/c_runtime_api.cc" */ /* #include "../../src/runtime/cpu_device_api.cc" */ @@ -43,4 +45,5 @@ #include "../../src/runtime/crt/graph_runtime.c" #include "../../src/runtime/crt/load_json.c" #include "../../src/runtime/crt/ndarray.c" +#include "../../src/runtime/crt/bundle.c" diff --git a/include/tvm/runtime/crt/common.h b/include/tvm/runtime/crt/common.h deleted file mode 100644 index 42952eb31a7f..000000000000 --- a/include/tvm/runtime/crt/common.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef COMMON_H_ -#define COMMON_H_ - -// #include "config.h" - -#include -#include -#include -#include -#include - -#ifndef __cplusplus - -/* typedef unsigned int size_t; */ -typedef unsigned char bool; -static const unsigned char false = 0; -static const unsigned char true = 1; - -#define nullptr ((void*)0) - -#endif // __cplusplus - -#define TVM_STATUS_SUCCESS (0) -#define TVM_STATUS_FAILURE (-1) - -#define API_BEGIN() int status; do { status = TVM_STATUS_SUCCESS; } while(false) -#define API_END() return status - -#if defined(WIN32) || defined(_WIN32) -#include -#ifndef __func__ -#define __func__ __FUNCTION__ -#endif -#define LOGE(fmt,...) \ - do { \ - char msgbuf[1024];sprintf(msgbuf,"ERROR: " fmt,##__VA_ARGS__); \ - MessageBoxA(NULL,msgbuf,"ERROR",MB_ICONERROR|MB_OK); \ - }while(0) -#define LOGW(fmt,...) \ - do { \ - char msgbuf[1024];sprintf(msgbuf,"WARNING: " fmt,##__VA_ARGS__); \ - MessageBoxA(NULL,msgbuf,"WARNING",MB_ICONWARNING|MB_OK); \ - }while(0) -#define LOGI(fmt,...) \ - do { \ - char msgbuf[1024];sprintf(msgbuf,"INFO: " fmt,##__VA_ARGS__); \ - MessageBoxA(NULL,msgbuf,"INFO",MB_ICONINFORMATION|MB_OK); \ - }while(0) -#elif defined(ANDROID) -#define LOG_TAG "TVMCRT" -#define LOGE(fmt,...) \ - do { \ - __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, \ - "ERROR: " fmt,##__VA_ARGS__); \ - }while(0) -#define LOGW(fmt,...) \ - do { \ - __android_log_print(ANDROID_LOG_WARN,LOG_TAG, \ - "WARNING: " fmt,##__VA_ARGS__); \ - }while(0) -#define LOGI(fmt,...) \ - do { \ - __android_log_print(ANDROID_LOG_INFO,LOG_TAG, \ - "INFO: " fmt,##__VA_ARGS__); \ - }while(0) -#elif defined(__linux__) || defined(__APPLE__) -#define LOGE(fmt,...) \ - do { \ - fprintf(stderr,"%s:%d: error: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ - exit(-1); \ - }while(0) -#define LOGW(fmt,...) \ - do { \ - fprintf(stderr,"%s:%d: warning: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ - }while(0) -#define LOGI(fmt,...) \ - do { \ - fprintf(stderr,"%s:%d: info: " fmt "\n",__FILE__,__LINE__,##__VA_ARGS__); \ - }while(0) -#else -#endif - -#define Printf printf - -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif // MAX - -static inline void NoOperation() {} -typedef void (*Function)(); - -static inline void Shape_Print(char * str, int64_t * shape, uint32_t ndim) { - uint32_t idx; - char tmp[10]; - for (idx = 0; idx < ndim; idx++) { - if (idx != (ndim-1)) { - sprintf(tmp, "%dx", (int)shape[idx]); - } else { - sprintf(tmp, "%d", (int)shape[idx]); - } - strcat(str, tmp); - } -} - -static inline uint32_t Shape_CountNonZero(int64_t * shape){ - uint32_t ndim; - for (ndim = 0; ndim < TVM_CRT_MAX_NDIM; ndim++) { - if (shape[ndim] == 0) { - break; - } - } - return ndim; -} - -static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim){ - int64_t accum = 1; - uint32_t idx; - for (idx = 0; idx < ndim; idx++) { - if (shape[idx] == 0) { break; } - accum *= shape[idx]; - } - return accum; -} - -//// seq class - -typedef struct seq_t { - uint32_t data[500]; - uint32_t size; - void (*push_back)(struct seq_t * seq, uint32_t src); - uint32_t * (*back)(struct seq_t * seq); - void (*pop_back)(struct seq_t * seq); -} Seq; - -static inline void SeqPush(Seq * seq, uint32_t src) { - if (seq->size >= 500) { - LOGE("seq too large."); - } - seq->data[seq->size] = src; - seq->size += 1; -} - -static inline uint32_t * SeqBack(Seq * seq) { - if (seq->size >= 500) { - LOGE("seq too large."); - } - return seq->data + (seq->size-1); -} - -static inline void SeqPop(Seq * seq) { - if (seq->size >= 500) { - Printf("seq size is too large.\n"); - } - if (seq->size == 0) { - Printf("seq size is too small.\n"); - } - seq->size -= 1; -} - -static inline Seq * SeqCreate() { - Seq * seq = (Seq*)malloc(sizeof(Seq)); - memset(seq, 0, sizeof(Seq)); - seq->push_back = SeqPush; - seq->back = SeqBack; - seq->pop_back = SeqPop; - return seq; -} - -#endif // COMMON_H_ diff --git a/include/tvm/runtime/crt/vm.h b/include/tvm/runtime/crt/vm.h index 853c72462dd1..f7f190b82679 100644 --- a/include/tvm/runtime/crt/vm.h +++ b/include/tvm/runtime/crt/vm.h @@ -1 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \file tvm/runtime/vm.h + * \brief A virtual machine for executing Relay programs. + */ +#ifndef TVM_RUNTIME_CRT_VM_H_ +#define TVM_RUNTIME_CRT_VM_H_ + /*! \brief Magic number for NDArray list file */ static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; + +#endif // TVM_RUNTIME_CRT_VM_H_ diff --git a/apps/bundle_deploy_c/bundle.c b/src/runtime/crt/bundle.c similarity index 93% rename from apps/bundle_deploy_c/bundle.c rename to src/runtime/crt/bundle.c index dee8b1f39e48..ae8b9d5d4ce7 100644 --- a/apps/bundle_deploy_c/bundle.c +++ b/src/runtime/crt/bundle.c @@ -17,10 +17,7 @@ * under the License. */ -/* #include */ -/* #include */ -/* #include */ -#include +#include "graph_runtime.h" extern unsigned char build_graph_json[]; extern unsigned int build_graph_json_len; diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c index 1a9f9508736d..3dc608830107 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/c_backend_api.c @@ -25,7 +25,7 @@ void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t nbytes, int dtype_code_hint, int dtype_bits_hint) { - void* ptr = nullptr; + void* ptr = 0; assert(nbytes > 0); unsigned int dtype_bytes = dtype_bits_hint / 8; #ifdef __ANDROID__ diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 189e4b6deaff..61f998709fc5 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -21,9 +21,23 @@ * \file graph_runtime.c * \brief implement graph runtime in pure C */ -#include +#include "graph_runtime.h" // #include +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif // MAX + +static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { + int64_t accum = 1; + uint32_t idx; + for (idx = 0; idx < ndim; idx++) { + if (shape[idx] == 0) { break; } + accum *= shape[idx]; + } + return accum; +} + /*! * \brief Get the input index given the name of input. * \param name The name of the input. @@ -31,7 +45,7 @@ */ int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { uint32_t i; - int32_t rv = -1; + int32_t rv = -1; for (i = 0; i< runtime->input_nodes_count; ++i) { uint32_t nid = runtime->input_nodes[i]; if (!strcmp(runtime->nodes[nid].name, name)) { @@ -40,7 +54,7 @@ int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { } } if (rv < 0) { - LOGE("cannot find \"%s\" among input", name); + fprintf(stderr, "cannot find \"%s\" among input", name); } return rv; } @@ -53,20 +67,20 @@ int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { void GraphRuntime_SetInput(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in) { uint32_t index = runtime->GetInputIndex(runtime, name); if (index >= runtime->input_nodes_count) { - LOGE("given index is greater than num of input nodes."); + fprintf(stderr, "given index is greater than num of input nodes."); } uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[index], 0); runtime->data_entry[eid].dl_tensor = *data_in; } int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param_blob, const uint32_t param_size) { - API_BEGIN(); + int status = 0; const char * bptr = param_blob; uint64_t header, reserved; header = ((uint64_t*)bptr)[0]; bptr += sizeof(header); if (header != kTVMNDArrayListMagic) { - LOGE("Invalid parameters file format"); + fprintf(stderr, "Invalid parameters file format"); } reserved = ((uint64_t*)bptr)[0]; bptr += sizeof(reserved); @@ -83,7 +97,7 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param name_length = ((uint64_t*)bptr)[0]; bptr += sizeof(name_length); if (name_length >= 80){ - LOGE("Error: function name longer than expected."); + fprintf(stderr, "Error: function name longer than expected."); } memcpy(names[idx], bptr, name_length); bptr += name_length; @@ -95,35 +109,32 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param bptr += sizeof(sz); uint32_t size = sz; if (size != names_count) { - LOGE("Invalid parameters file format"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Invalid parameters file format"); + status = -1; } for (idx = 0; idx < size; idx++) { int32_t in_idx = runtime->GetInputIndex(runtime, names[idx]); if (!(in_idx >= 0)) { - LOGE("Found param for non-existent input: %s", names[idx]); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Found param for non-existent input: %s", names[idx]); + status = -1; } uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[in_idx], 0); if (!(eid < runtime->data_entry_count)) { - LOGE("`entry_id`=%d is greater than expected(%d).", eid, runtime->data_entry_count); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "`entry_id`=%d is greater than expected(%d).", eid, runtime->data_entry_count); + status = -1; } status |= NDArray_Load(&(runtime->data_entry[eid]), &bptr); #if TVM_CRT_DEBUG - char shape_desc[20]; - memset(shape_desc, 0, sizeof(shape_desc)); NDArray * entry = &(runtime->data_entry[eid]); - Shape_Print(shape_desc, entry->dl_tensor.shape, entry->dl_tensor.ndim); - LOGI("param %s loaded, in_idx=%d, eid=%d, ndim=%d, shape=%s, data[0]=%f", - names[idx], in_idx, eid, entry->dl_tensor.ndim, shape_desc, + printf("param %s loaded, in_idx=%d, eid=%d, ndim=%d, data[0]=%f\n", + names[idx], in_idx, eid, entry->dl_tensor.ndim, ((float*)entry->dl_tensor.data)[0]); #endif // TVM_CRT_DEBUG } - - API_END(); + + return status; } /*! @@ -135,7 +146,7 @@ void GraphRuntime_Run(GraphRuntime * runtime) { for (idx = 0; idx < runtime->op_execs_count; ++idx) { if (runtime->op_execs[idx].fexec) { #if TVM_CRT_DEBUG - LOGI("calling %s (%d)", runtime->op_execs[idx].name, idx); + printf("calling %s (%d)\n", runtime->op_execs[idx].name, idx); #endif // TVM_CRT_DEBUG runtime->op_execs[idx].Call(&(runtime->op_execs[idx])); } @@ -143,7 +154,7 @@ void GraphRuntime_Run(GraphRuntime * runtime) { } int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * out) { - int status = TVM_STATUS_SUCCESS; + int status = 0; uint32_t nid = runtime->outputs[idx].node_id; uint32_t index = runtime->outputs[idx].index; uint32_t eid = runtime->GetEntryId(runtime, nid, index); @@ -161,7 +172,7 @@ int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * void GraphRuntime_SetupStorage(GraphRuntime * runtime) { uint32_t idx, dim; - + // Grab saved optimization plan from graph. DLDataType vtype[GRAPH_RUNTIME_MAX_NODES]; GraphRuntimeGraphAttr * attrs = &(runtime->attrs); @@ -178,16 +189,11 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { int storage_id = attrs->storage_id[idx]; // Use the fallback device if no device index is available. int device_type = runtime->ctxs[0].device_type; - uint32_t size = 1; - for (dim = 0; dim < TVM_CRT_MAX_NDIM; dim++) { - if (attrs->shape[idx][dim] != 0){ - size *= attrs->shape[idx][dim]; - } - } + uint32_t size = Shape_Accumulate(attrs->shape[idx], attrs->ndim[idx]); DLDataType t = vtype[idx]; uint32_t bits = t.bits * t.lanes; size_t bytes = ((bits + 7U) / 8U) * size; - + uint32_t sid = storage_id; if (sid >= pool_entry_count) { pool_entry_count = sid + 1; @@ -205,7 +211,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { shape[0] = (pit.size + 3) / 4; runtime->storage_pool[runtime->storage_pool_count] = NDArray_Empty(1, shape, dtype, ctx); if (runtime->storage_pool[runtime->storage_pool_count].dl_tensor.data == 0) { - LOGE("fail to create storage_pool with idx=%d", idx); + fprintf(stderr, "fail to create storage_pool with idx=%d\n", idx); } runtime->storage_pool_count++; } @@ -218,15 +224,15 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { size_t storage_id = attrs->storage_id[idx]; assert(storage_id < runtime->storage_pool_count); runtime->data_entry[idx] = - NDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], vtype[idx]); + NDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], attrs->ndim[idx], vtype[idx]); if (runtime->data_entry[idx].dl_tensor.data == 0) { - LOGE("fail to create for node with idx=%d, storage_id=%d", idx, storage_id); + fprintf(stderr, "fail to create for node with idx=%d, storage_id=%d\n", idx, storage_id); } } } int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { - API_BEGIN(); + int status = 0; uint32_t nid, idx; runtime->op_execs_count = runtime->nodes_count; for (nid = 0; nid < runtime->nodes_count; nid++) { @@ -246,23 +252,24 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { args_count ++; } if (strcmp(inode->op_type, "tvm_op")) { - LOGE("Can only take tvm_op as op"); status = TVM_STATUS_FAILURE; + fprintf(stderr, "Can only take tvm_op as op\n"); status = -1; break; } if (args_count >= TVM_CRT_MAX_ARGS) { - LOGE("too many arguments: expected less than %d args, but got %d.", TVM_CRT_MAX_ARGS, args_count); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "too many arguments: expected less than %d args, but got %d.\n", + TVM_CRT_MAX_ARGS, args_count); + status = -1; break; } #if TVM_CRT_DEBUG - LOGI("creating tvm_op: %s with node_id=%d", inode->param.func_name, nid); + printf("creating tvm_op: %s with node_id=%d\n", inode->param.func_name, nid); #endif // TVM_CRT_DEBUG PackedFunc pf; runtime->CreateTVMOp(runtime, &(inode->param), args, args_count, inode->inputs_count, &pf); runtime->op_execs[nid] = pf; } } - API_END(); + return status; } typedef struct opargs_t { @@ -277,7 +284,7 @@ typedef struct opargs_t { } OpArgs; int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * param, - DLTensorPtr * args, const uint32_t args_count, + DLTensorPtr * args, const uint32_t args_count, uint32_t num_inputs, PackedFunc * pf) { uint32_t idx; OpArgs arg_ptr; @@ -306,14 +313,14 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para } } if (!strcmp(param->func_name, "__nop") || !strcmp(param->func_name, "__copy")) { - LOGE("%s function is not yet supported.", param->func_name); + fprintf(stderr, "%s function is not yet supported.", param->func_name); } - + runtime->module.GetFunction(param->func_name, pf); TVMArgs targs = TVMArgs_Create(arg_ptr.arg_values, arg_ptr.arg_tcodes, arg_ptr.arg_values_count); pf->SetArgs(pf, &targs); - - return TVM_STATUS_SUCCESS; + + return 0; } /*! @@ -332,6 +339,7 @@ void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, runtime->SetupStorage(runtime); PackedFunc_SetupExecs(); runtime->SetupOpExecs(runtime); + JSONReader_Release(&reader); } GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, diff --git a/include/tvm/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h similarity index 74% rename from include/tvm/runtime/crt/graph_runtime.h rename to src/runtime/crt/graph_runtime.h index a2440d03d622..d266336a387b 100644 --- a/include/tvm/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -6,9 +6,9 @@ * to you 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 @@ -25,11 +25,11 @@ #define TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ #include -#include -#include -#include -// #include "io.h" -#include + +#include "load_json.h" // +#include "ndarray.h" // +#include "packed_func.h" // +#include "module.h" // /*! \brief macro to do C API call */ #define TVM_CCALL(func) \ @@ -46,7 +46,7 @@ typedef struct tvm_op_param_t { uint32_t num_outputs; uint32_t flatten_data; } TVMOpParam; - + // Memory pool entry. typedef struct graph_runtime_pool_entry_t { size_t size; @@ -63,15 +63,21 @@ typedef struct graph_runtime_node_entry_t { } NodeEntry; static inline int NodeEntry_Load(NodeEntry * entry, JSONReader * reader) { - int status = TVM_STATUS_SUCCESS; + int status = 0; reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("invalid json format: failed to parse `node_id`"); } + if (!(reader->NextArrayItem(reader))) { + fprintf(stderr, "invalid json format: failed to parse `node_id`\n"); + } reader->ReadUnsignedInteger(reader, &(entry->node_id)); - if (!(reader->NextArrayItem(reader))) { LOGE("invalid json format: failed to parse `index`"); } + if (!(reader->NextArrayItem(reader))) { + fprintf(stderr, "invalid json format: failed to parse `index`\n"); + } reader->ReadUnsignedInteger(reader, &(entry->index)); if (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(entry->version)); - if (reader->NextArrayItem(reader)) { LOGE("invalid json format: failed to parse `version`"); } + if (reader->NextArrayItem(reader)) { + fprintf(stderr, "invalid json format: failed to parse `version`\n"); + } } else { entry->version = 0; } @@ -97,7 +103,8 @@ typedef struct graph_runtime_node_t { int (*Load)(struct graph_runtime_node_t * node, JSONReader *reader); } GraphRuntimeNode; -static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, TVMOpParam* param) { +static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, + TVMOpParam* param) { int bitmask = 0; char key[20], value[120]; memset(param, 0, sizeof(TVMOpParam)); @@ -107,27 +114,26 @@ static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReade while (reader->NextObjectItem(reader, key)) { reader->ReadString(reader, value); if (!strcmp(key, "func_name")) { - /* param->func_name = value; */ strcpy(param->func_name, value); bitmask |= 1; } else if (!strcmp(key, "num_inputs")) { - param->num_inputs = strtoul(value, nullptr, 10); + param->num_inputs = strtoul(value, 0, 10); bitmask |= 2; } else if (!strcmp(key, "num_outputs")) { - param->num_outputs = strtoul(value, nullptr, 10); + param->num_outputs = strtoul(value, 0, 10); bitmask |= 4; } else if (!strcmp(key, "flatten_data")) { - param->flatten_data = strtoul(value, nullptr, 10); + param->flatten_data = strtoul(value, 0, 10); bitmask |= 8; } else { - LOGE("do not support key %s", key); + fprintf(stderr, "do not support key %s", key); } } - if (bitmask != (1|2|4|8)) { LOGE("invalid format"); } + if (bitmask != (1|2|4|8)) { fprintf(stderr, "invalid format\n"); } } static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *reader) { - int status = TVM_STATUS_SUCCESS; + int status = 0; reader->BeginObject(reader); int bitmask = 0; char key[20]; @@ -141,8 +147,8 @@ static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *rea } else if (!strcmp(key, "inputs")) { size_t count = node->inputs_count; if (count >= GRAPH_RUNTIME_NODE_MAX_INPUTS) { - LOGE("The number of inputs in graph runtime node is greater than expected."); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "The number of inputs in graph runtime node is greater than expected.\n"); + status = -1; break; } reader->BeginArray(reader); @@ -150,22 +156,22 @@ static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *rea NodeEntry * inputs = node->inputs + count; reader->BeginArray(reader); if (!reader->NextArrayItem(reader)) { - LOGE("invalid json format"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "invalid json format\n"); + status = -1; break; } reader->ReadUnsignedInteger(reader, &(inputs->node_id)); if (!reader->NextArrayItem(reader)) { - LOGE("invalid json format"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "invalid json format\n"); + status = -1; break; } reader->ReadUnsignedInteger(reader, &(inputs->index)); - if (reader->NextArrayItem(reader)) { + if (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(inputs->version)); if (reader->NextArrayItem(reader)) { - LOGE("invalid json format"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "invalid json format\n"); + status = -1; break; } } else { @@ -181,15 +187,15 @@ static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *rea GraphRuntimeNode_LoadAttrs(node, reader, ¶m); memcpy(&node->param, ¶m, sizeof(param)); } else if (!strcmp(key, "control_deps")) { - LOGE("do not support key %s", key); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "do not support key %s", key); + status = -1; } else { - LOGE("do not support key %s", key); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "do not support key %s", key); + status = -1; } - if (status != TVM_STATUS_SUCCESS) { break; } + if (status != 0) { break; } } - if (bitmask != (1|2|4)) { LOGE("invalid format"); } + if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } return status; } @@ -209,11 +215,12 @@ typedef struct graph_runtime_graph_attr_t { char dltype[GRAPH_RUNTIME_MAX_NODES][10]; // "int8", "int16", "float32" uint32_t dltype_count; int64_t shape[GRAPH_RUNTIME_MAX_NODES][TVM_CRT_MAX_NDIM]; + uint32_t ndim[GRAPH_RUNTIME_MAX_NODES]; uint32_t shape_count; } GraphRuntimeGraphAttr; static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONReader *reader) { - int status = TVM_STATUS_SUCCESS; + int status = 0; int bitmask = 0; char key[16], type[16]; uint32_t storage_id_count = 0; @@ -224,52 +231,53 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR while (reader->NextObjectItem(reader, key)) { if (!strcmp(key, "dltype")) { reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->ReadString(reader, type); - if (strcmp(type, "list_str")) { LOGE("Invalid json format"); } - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (strcmp(type, "list_str")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { reader->ReadString(reader, attr->dltype[dltype_count]); dltype_count ++; } attr->dltype_count = dltype_count;; - if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } bitmask |= 1; } else if (!strcmp(key, "storage_id")) { reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->ReadString(reader, type); - if (strcmp(type, "list_int")) { LOGE("Invalid json format"); } - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(attr->storage_id[storage_id_count])); storage_id_count++; } - if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } bitmask |= 2; } else if (!strcmp(key, "shape")) { reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->ReadString(reader, type); - if (strcmp(type, "list_shape")) { LOGE("Invalid json format"); } - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (strcmp(type, "list_shape")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { reader->BeginArray(reader); reader->ReadInteger(reader, &(attr->shape[shape_count][0])); - if (reader->NextArrayItem(reader)) { - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][1])); - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][2])); - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][3])); - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][4])); - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][5])); + uint32_t ndim = 1; + if (reader->NextArrayItem(reader)) { + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][1])); ndim ++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][2])); ndim ++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][3])); ndim ++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][4])); ndim ++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][5])); ndim ++; reader->NextArrayItem(reader); } } @@ -277,28 +285,29 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR } } } + attr->ndim[shape_count] = ndim; shape_count ++; } attr->shape_count = shape_count; - if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } bitmask |= 4; } else if (!strcmp(key, "device_index")) { reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->ReadString(reader, type); - if (strcmp(type, "list_int")) { LOGE("Invalid json format"); } - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } while (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(attr->device_index[device_index_count])); device_index_count ++; } - if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } } else { reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } reader->ReadString(reader, type); if (!strcmp(type, "list_int")) { - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } uint32_t temp[GRAPH_RUNTIME_MAX_NODES]; uint32_t temp_count = 0; reader->BeginArray(reader); @@ -307,16 +316,16 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR temp_count ++; } } else if (!strcmp(type, "size_t")) { - if (!(reader->NextArrayItem(reader))) { LOGE("Invalid json format"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } uint32_t temp; reader->ReadUnsignedInteger(reader, &temp); } else { - LOGE("cannot skip graph attr %s", key); + fprintf(stderr, "cannot skip graph attr %s", key); } - if (reader->NextArrayItem(reader)) { LOGE("Invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } } } - if (bitmask != (1|2|4)) { LOGE("invalid format"); } + if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } return status; } @@ -370,15 +379,16 @@ typedef struct graph_runtime_t { * \brief Load parameters from parameter blob. * \param param_blob A binary blob of parameter. */ - int (*LoadParams)(struct graph_runtime_t * runtime, const char * param_blob, const uint32_t param_size); - + int (*LoadParams)(struct graph_runtime_t * runtime, const char * param_blob, + const uint32_t param_size); + // The graph attribute fields. int (*Load)(struct graph_runtime_t * runtime, JSONReader *reader); /*! \brief Setup the temporal storage */ void (*SetupStorage)(struct graph_runtime_t * runtime); /*! \brief Setup the executors. */ int (*SetupOpExecs)(struct graph_runtime_t * runtime); - + /*! * \brief Create an execution function given input. * \param attrs The node attributes. @@ -389,10 +399,10 @@ typedef struct graph_runtime_t { int32_t (*CreateTVMOp)(struct graph_runtime_t * runtime, const TVMOpParam * attrs, DLTensorPtr * args, const uint32_t args_count, uint32_t num_inputs, PackedFunc * pf); - + // Get node entry index. uint32_t (*GetEntryId)(struct graph_runtime_t * runtime, uint32_t nid, uint32_t index); - + // /*! \brief The graph nodes. */ /* GraphRuntimeNode nodes_[GRAPH_RUNTIME_MAX_NODES]; */ GraphRuntimeNode nodes[GRAPH_RUNTIME_MAX_NODES]; @@ -425,7 +435,7 @@ typedef struct graph_runtime_t { } GraphRuntime; static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) { - int status = TVM_STATUS_SUCCESS; + int status = 0; reader->BeginObject(reader); int bitmask = 0; /* String key = StringCreate(); */ @@ -436,12 +446,12 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) while (reader->NextArrayItem(reader)) { GraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; status = GraphRuntimeNode_Load(node, reader); - if (status != TVM_STATUS_SUCCESS) { - LOGE("Fail to load an element in `nodes` field in graph runtime node."); + if (status != 0) { + fprintf(stderr, "failed to load an element in `nodes` field in graph runtime node.\n"); break; #if TVM_CRT_DEBUG } else { - LOGI("layer %u: `%s` loaded.", runtime->nodes_count, node->name); + printf("layer %u: `%s` loaded.\n", runtime->nodes_count, node->name); #endif // TVM_CRT_DEBUG } runtime->nodes_count ++; /* seq push */ @@ -469,37 +479,39 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) while (reader->NextArrayItem(reader)) { NodeEntry * entry = runtime->outputs + runtime->outputs_count; status = NodeEntry_Load(entry, reader); - if (status != TVM_STATUS_SUCCESS) { - LOGE("Fail to load an element in `heads` field in graph runtime node."); + if (status != 0) { + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node."); break; } runtime->outputs_count ++; /* seq push */ - } + } bitmask |= 8; } else if (!strcmp(key, "attrs")) { status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); - if (status != TVM_STATUS_SUCCESS) { - LOGE("Fail to load an element in `heads` field in graph runtime node."); + if (status != 0) { + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node."); break; } bitmask |= 16; } else if (!strcmp(key, "metadata")) { break; } else { - LOGE("key %s is not supported", key); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "key %s is not supported", key); + status = -1; } - if (status != TVM_STATUS_SUCCESS) { break; } + if (status != 0) { break; } } - if (!(bitmask == (1|2|4|8|16))) { LOGE("invalid format"); } + if (!(bitmask == (1|2|4|8|16))) { fprintf(stderr, "invalid format\n"); } return status; } -static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, uint32_t nid, uint32_t index) { +static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, + uint32_t nid, uint32_t index) { return runtime->node_row_ptr[nid] + index; } -GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, const TVMContext * ctxs); +GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, + const TVMContext * ctxs); void TVMGraphRuntimeRelease(GraphRuntime ** runtime); diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index e6ebb90ee2c7..cd85607bcf65 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -6,9 +6,9 @@ * to you 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 @@ -21,7 +21,7 @@ * \file saveload_json.cc * \brief Save and load graph to/from JSON file. */ -#include +#include "load_json.h" // the node entry structure in serialized format typedef struct _JSONNodeEntry { @@ -33,13 +33,13 @@ typedef struct _JSONNodeEntry { void JSONNodeEntryLoad(JSONNodeEntry * entry, JSONReader *reader) { reader->BeginArray(reader); - if (reader->NextArrayItem(reader)) { Printf("invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "invalid json format\n"); } reader->ReadUnsignedInteger(reader, &(entry->node_id)); - if (reader->NextArrayItem(reader)) { Printf("invalid json format"); } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "invalid json format\n"); } reader->ReadUnsignedInteger(reader, &(entry->index)); if (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(entry->version)); - if (!reader->NextArrayItem(reader)) { Printf("invalid json format"); } + if (!reader->NextArrayItem(reader)) { fprintf(stderr, "invalid json format\n"); } } else { entry->version = 0; } diff --git a/include/tvm/runtime/crt/load_json.h b/src/runtime/crt/load_json.h similarity index 78% rename from include/tvm/runtime/crt/load_json.h rename to src/runtime/crt/load_json.h index 9a31cf33a7a1..fe4c100d3209 100644 --- a/include/tvm/runtime/crt/load_json.h +++ b/src/runtime/crt/load_json.h @@ -18,13 +18,14 @@ */ /*! - * \file json.h + * \file load_json.h * \brief Lightweight JSON Reader that read save into C++ data structs. */ #ifndef LOAD_JSON_H_ #define LOAD_JSON_H_ -#include "common.h" +#include +#include enum { JSON_READ_TYPE_U8 = 1, @@ -40,6 +41,56 @@ enum { JSON_READ_TYPE_GRAPH_RUNTIME_GRAPH_ATTR = 11 }; +typedef struct seq_t { + uint32_t * data; + uint64_t allocated; + uint32_t size; + void (*push_back)(struct seq_t * seq, uint32_t src); + uint32_t * (*back)(struct seq_t * seq); + void (*pop_back)(struct seq_t * seq); +} Seq; + +static inline void SeqPush(Seq * seq, uint32_t src) { + if (seq->size >= seq->allocated) { + printf("seq too large.\n"); + } + seq->data[seq->size] = src; + seq->size += 1; +} + +static inline uint32_t * SeqBack(Seq * seq) { + if (seq->size >= seq->allocated) { + printf("seq too large.\n"); + } + return seq->data + (seq->size-1); +} + +static inline void SeqPop(Seq * seq) { + if (seq->size >= seq->allocated) { + printf("seq size is too large.\n"); + } + if (seq->size == 0) { + printf("seq size is too small.\n"); + } + seq->size -= 1; +} + +static inline Seq * SeqCreate(uint64_t len) { + Seq * seq = (Seq*)malloc(sizeof(Seq)); + memset(seq, 0, sizeof(Seq)); + seq->allocated = len; + seq->data = (uint32_t*)malloc(sizeof(uint32_t)*len); + seq->push_back = SeqPush; + seq->back = SeqBack; + seq->pop_back = SeqPop; + return seq; +} + +static inline void SeqRelease(Seq ** seq) { + free((*seq)->data); + free(*seq); +} + /*! * \brief Lightweight JSON Reader to read any STL compositions and structs. * The user need to know the schema of the @@ -68,8 +119,8 @@ typedef struct json_reader_t { int (*ReadString)(struct json_reader_t * reader, char * out_value); void (*BeginArray)(struct json_reader_t * reader); void (*BeginObject)(struct json_reader_t * reader); - bool (*NextObjectItem)(struct json_reader_t * reader, char * out_key); - bool (*NextArrayItem)(struct json_reader_t * reader); + uint8_t (*NextObjectItem)(struct json_reader_t * reader, char * out_key); + uint8_t (*NextArrayItem)(struct json_reader_t * reader); } JSONReader; typedef void (*ReadFunction)(JSONReader *reader, void *addr); @@ -81,7 +132,7 @@ struct JSONObjectReadHelperEntry { /*! \brief the address to read */ void *addr; /*! \brief whether it is optional */ - bool optional; + uint8_t optional; }; /*! @@ -170,7 +221,7 @@ static inline char JSONReader_NextNonSpace(JSONReader * reader) { */ static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { int ch; - while (true) { + while (1) { ch = reader->PeekNextChar(reader); if (ch == '\n') { ++(reader->line_count_n_); } if (ch == '\r') { ++(reader->line_count_r_); } @@ -186,12 +237,12 @@ static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { * \throw dmlc::Error when next token is not string */ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { - int status = TVM_STATUS_SUCCESS; + int status = 0; char ch = reader->NextNonSpace(reader); char output[128]; uint32_t output_counter = 0; memset(output, 0, 128); - while (true) { + while (1) { ch = reader->NextChar(reader); if (ch == '\\') { char sch = reader->NextChar(reader); @@ -201,25 +252,25 @@ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { case '\\': strcat(output, "\\"); break; case 't': strcat(output, "\t"); break; case '\"': strcat(output, "\""); break; - default: LOGE("unknown string escape \%c", sch); + default: fprintf(stderr, "unknown string escape \%c\n", sch); } } else { if (ch == '\"') { break; } if (strlen(output) >= 127) { - LOGE("Error: detected buffer overflow."); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Error: detected buffer overflow.\n"); + status = -1; break; } strncat(output, &ch, 1); output_counter++; if (output_counter >= 127) { - LOGE("Error: string size greater than 128."); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Error: string size greater than 128.\n"); + status = -1; break; } } if (ch == EOF || ch == '\r' || ch == '\n') { - LOGE("Error at line X, Expect \'\"\' but reach end of line"); + fprintf(stderr, "Error at line X, Expect \'\"\' but reach end of line\n"); } } strcpy(out_str, output); @@ -227,9 +278,9 @@ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { } static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { - int status = TVM_STATUS_SUCCESS; + int status = 0; char* endptr; - const char* icstr = reader->isptr; // ->data_; + const char* icstr = reader->isptr; unsigned int number = strtol(icstr, &endptr, 10); reader->isptr += endptr - icstr; *out_value = number; @@ -238,9 +289,9 @@ static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned i static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { - int status = TVM_STATUS_SUCCESS; + int status = 0; char* endptr; - const char* icstr = reader->isptr; // ->data_; + const char* icstr = reader->isptr; int64_t number = strtol(icstr, &endptr, 10); reader->isptr += endptr - icstr; *out_value = number; @@ -263,7 +314,7 @@ static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_valu static inline void JSONReader_BeginObject(JSONReader * reader) { int ch = reader->NextNonSpace(reader); if (!(ch == '{')) { - LOGE("Error at line X, Expect \'{\' but got \'%c\'", ch); + fprintf(stderr, "Error at line X, Expect \'{\' but got \'%c\'\n", ch); } Seq * scope_counter_ = reader->scope_counter_; scope_counter_->push_back(scope_counter_, 0); @@ -276,38 +327,38 @@ static inline void JSONReader_BeginObject(JSONReader * reader) { * \param out_key the key to the next object. * \return true if the read is successful, false if we are at end of the object. */ -static inline bool JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { - bool next = true; +static inline uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { + uint8_t next = 1; Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { int ch = reader->NextNonSpace(reader); if (ch == EOF) { - next = false; + next = 0; } else if (ch == '}') { - next = false; + next = 0; } else { if (ch != ',') { - LOGE("Error at line X, JSON object expect \'}\' or \',\' but got \'%c\'", ch); + fprintf(stderr, "Error at line X, JSON object expect \'}\' or \',\' but got \'%c\'\n", ch); } } } else { int ch = reader->PeekNextNonSpace(reader); if (ch == '}') { reader->NextChar(reader); - next = false; + next = 0; } } if (!next) { scope_counter_->pop_back(scope_counter_); - return false; + return 0; } else { scope_counter_->back(scope_counter_)[0] += 1; reader->ReadString(reader, out_key); int ch = reader->NextNonSpace(reader); if (ch != ':') { - LOGE("Error at line X, Expect \':\' but get \'%c\'", ch); + fprintf(stderr, "Error at line X, Expect \':\' but get \'%c\'\n", ch); } - return true; + return 1; } } @@ -325,7 +376,7 @@ static inline bool JSONReader_NextObjectItem(JSONReader * reader, char * out_key static inline void JSONReader_BeginArray(JSONReader * reader) { int ch = reader->NextNonSpace(reader); if (ch != '[') { - LOGE("Error at line X, Expect \'[\' but get \'%c\'", ch); + fprintf(stderr, "Error at line X, Expect \'[\' but get \'%c\'\n", ch); } Seq * scope_counter_ = reader->scope_counter_; scope_counter_->push_back(scope_counter_, 0); @@ -337,33 +388,33 @@ static inline void JSONReader_BeginArray(JSONReader * reader) { * reader->Read to read in the value. * \return true if the read is successful, false if we are at end of the array. */ -static inline bool JSONReader_NextArrayItem(JSONReader * reader) { - bool next = true; +static inline uint8_t JSONReader_NextArrayItem(JSONReader * reader) { + uint8_t next = 1; Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { int ch = reader->NextNonSpace(reader); if (ch == EOF) { - next = false; + next = 0; } else if (ch == ']') { - next = false; + next = 0; } else { if (ch != ',') { - LOGE("Error at line X, JSON object expect \']\' or \',\' but got \'%c\'", ch); + fprintf(stderr, "Error at line X, JSON object expect \']\' or \',\' but got \'%c\'\n", ch); } } } else { int ch = reader->PeekNextNonSpace(reader); if (ch == ']') { reader->NextChar(reader); - next = false; + next = 0; } } if (!next) { scope_counter_->pop_back(scope_counter_); - return false; + return 0; } else { scope_counter_->back(scope_counter_)[0] += 1; - return true; + return 1; } } @@ -372,9 +423,9 @@ static inline bool JSONReader_NextArrayItem(JSONReader * reader) { * \param is the input source. */ static inline JSONReader JSONReader_Create(const char * is) { - JSONReader reader; // = (JSONReader*)malloc(sizeof(JSONReader)); + JSONReader reader; memset(&reader, 0, sizeof(JSONReader)); - reader.scope_counter_ = SeqCreate(); + reader.scope_counter_ = SeqCreate(200); reader.NextChar = JSONReader_NextChar; reader.PeekNextChar = JSONReader_PeekNextChar; reader.NextNonSpace = JSONReader_NextNonSpace; @@ -386,8 +437,6 @@ static inline JSONReader JSONReader_Create(const char * is) { reader.BeginObject = JSONReader_BeginObject; reader.NextArrayItem = JSONReader_NextArrayItem; reader.NextObjectItem = JSONReader_NextObjectItem; - // strcpy(reader.is_, is); - // TODO(liangfu): release memory reader.is_ = (char*)malloc(strlen(is)+1); memset(reader.is_, 0, strlen(is)+1); strcpy(reader.is_, is); @@ -395,4 +444,9 @@ static inline JSONReader JSONReader_Create(const char * is) { return reader; } +static inline void JSONReader_Release(JSONReader * reader) { + SeqRelease(&(reader->scope_counter_)); + free(reader->is_); +} + #endif // LOAD_JSON_H_ diff --git a/include/tvm/runtime/crt/module.h b/src/runtime/crt/module.h similarity index 98% rename from include/tvm/runtime/crt/module.h rename to src/runtime/crt/module.h index 5378cd951a43..c622c519bbe2 100644 --- a/include/tvm/runtime/crt/module.h +++ b/src/runtime/crt/module.h @@ -26,7 +26,6 @@ #include #include -#include struct packed_func_t; typedef struct packed_func_t PackedFunc; diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index da0557561de6..b981719bdff6 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -22,56 +22,10 @@ * \brief NDArray container infratructure. */ -#include -#include -#include -#include -//#include +#include "ndarray.h" -NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype) { - uint32_t ndim = Shape_CountNonZero(shape); +NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, uint32_t ndim, DLDataType dtype) { NDArray ret = NDArray_Create(ndim, shape, dtype, arr->dl_tensor.ctx); ret.dl_tensor.data = arr->dl_tensor.data; return ret; } - -int TVMArrayAlloc(const tvm_index_t* shape, - int ndim, - int dtype_code, - int dtype_bits, - int dtype_lanes, - int device_type, - int device_id, - TVMArrayHandle * out) { - API_BEGIN(); - uint32_t idx = 0; - DLDataType dtype; - dtype.code = dtype_code; - dtype.bits = dtype_bits; - dtype.lanes = dtype_lanes; - DLContext ctx; - ctx.device_type = device_type; - ctx.device_id = device_id; - (*out)->ctx = ctx; - (*out)->ndim = ndim; - (*out)->dtype = dtype; - uint32_t bytes = (dtype_bits + 7) / 8; - uint32_t size = 1; - for (idx = 0; idx < ndim; idx++) { - size *= shape[idx]; - } - (*out)->data = TVMBackendAllocWorkspace(device_type, device_id, size, dtype_code, dtype_bits); - memset((*out)->data, 0, size * bytes); - for (idx = 0; idx < ndim; idx++) { - (*out)->shape[idx] = shape[idx]; - (*out)->strides = 0; - } - (*out)->byte_offset = 0; - API_END(); -} - -int TVMArrayFree(TVMArrayHandle handle) { - API_BEGIN(); - API_END(); -} - diff --git a/include/tvm/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h similarity index 84% rename from include/tvm/runtime/crt/ndarray.h rename to src/runtime/crt/ndarray.h index 07e95e7b395e..d178cb23eab0 100644 --- a/include/tvm/runtime/crt/ndarray.h +++ b/src/runtime/crt/ndarray.h @@ -26,9 +26,12 @@ #include #include -#include #include +#include +#include +#include + /*! \brief Magic number for NDArray file */ static const uint64_t kTVMNDArrayMagic = 0xDD5E40F096B4A13F; @@ -36,7 +39,7 @@ typedef struct ndarray_t { DLTensor dl_tensor; } NDArray; -NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, DLDataType dtype); +NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, uint32_t ndim, DLDataType dtype); static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx) { NDArray ret; @@ -64,12 +67,12 @@ static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType d } static inline int NDArray_Load(NDArray * ret, const char ** strm) { - int32_t status = TVM_STATUS_SUCCESS; + int32_t status = 0; uint64_t header, reserved; header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); if (header != kTVMNDArrayMagic) { - LOGE("Invalid DLTensor file format\n"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Invalid DLTensor file format\n"); + status = -1; } reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); DLContext ctx; @@ -79,12 +82,12 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); if ((ndim <= 0) || (ndim > TVM_CRT_MAX_NDIM)) { - LOGE("Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); + status = -1; } if (ctx.device_type != kDLCPU) { - LOGE("Invalid DLTensor context: can only save as CPU tensor\n"); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "Invalid DLTensor context: can only save as CPU tensor\n"); + status = -1; } int64_t shape[TVM_CRT_MAX_NDIM]; // [ndim]; uint32_t idx; @@ -102,9 +105,10 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { int64_t data_byte_size; data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); if (!(data_byte_size == num_elems * elem_bytes)) { - LOGE("invalid DLTensor file format: data_byte_size=%ld, while num_elems*elem_bytes=%ld", - data_byte_size, (num_elems * elem_bytes)); - status = TVM_STATUS_FAILURE; + fprintf(stderr, "invalid DLTensor file format: data_byte_size=%ld, " + "while num_elems*elem_bytes=%ld\n", + data_byte_size, (num_elems * elem_bytes)); + status = -1; } memcpy(ret->dl_tensor.data, *strm, data_byte_size); *strm += data_byte_size; diff --git a/include/tvm/runtime/crt/packed_func.h b/src/runtime/crt/packed_func.h similarity index 72% rename from include/tvm/runtime/crt/packed_func.h rename to src/runtime/crt/packed_func.h index 1e8691f05628..a943f6b868f5 100644 --- a/include/tvm/runtime/crt/packed_func.h +++ b/src/runtime/crt/packed_func.h @@ -24,29 +24,12 @@ #ifndef TVM_RUNTIME_PACKED_FUNC_H_ #define TVM_RUNTIME_PACKED_FUNC_H_ -// #ifndef _LIBCPP_SGX_NO_IOSTREAMS -// #include -// #endif -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include #include -#include -#include -// #include "node_base.h" -// namespace HalideIR { -// // Forward declare type for extensions -// // The header works fine without depending on this. -// struct Type; -// struct Expr; -// } +#include +#include + +#include "module.h" // Whether use TVM runtime in header only mode. #ifndef TVM_RUNTIME_HEADER_ONLY @@ -57,19 +40,19 @@ static inline DLDataType String2DLDataType(const char * s) { DLDataType t; // handle None type if (strlen(s) == 0) { - t.bits = 0; t.lanes = 0; t.code = kTVMOpaqueHandle; // kHandle; + t.bits = 0; t.lanes = 0; t.code = kTVMOpaqueHandle; return t; } t.bits = 32; t.lanes = 1; const char* scan; - if (!strncmp(s, "int", 3)) { // s.substr(0, 3) == "int" + if (!strncmp(s, "int", 3)) { t.code = kDLInt; scan = s + 3; - } else if (!strncmp(s, "uint", 4)) { // s.substr(0, 4) == "uint" + } else if (!strncmp(s, "uint", 4)) { t.code = kDLUInt; scan = s + 4; - } else if (!strncmp(s, "float", 5)) { // s.substr(0, 5) == "float" + } else if (!strncmp(s, "float", 5)) { t.code = kDLFloat; scan = s + 5; - } else if (!strncmp(s, "handle", 6)) { // s.substr(0, 6) == "handle" - t.code = kTVMOpaqueHandle; // kHandle; + } else if (!strncmp(s, "handle", 6)) { + t.code = kTVMOpaqueHandle; t.bits = 64; // handle uses 64 bit by default. scan = s + 6; } else if (!strcmp(s, "bool")) { @@ -79,10 +62,9 @@ static inline DLDataType String2DLDataType(const char * s) { return t; } else { scan = s; - // LOG(FATAL) << "unknown type " << s; - LOGE("unknown type %s\n", s); + fprintf(stderr, "unknown type %s\n", s); } - char* xdelim; // emulate sscanf("%ux%u", bits, lanes) + char* xdelim; uint8_t bits = (uint8_t)(strtoul(scan, &xdelim, 10)); if (bits != 0) t.bits = bits; char* endpt = xdelim; @@ -90,7 +72,7 @@ static inline DLDataType String2DLDataType(const char * s) { t.lanes = (uint16_t)(strtoul(xdelim + 1, &endpt, 10)); } if (!(endpt == s + strlen(s))){ - LOGE("unknown type %s\n", s); + fprintf(stderr, "unknown type %s\n", s); } return t; } @@ -115,15 +97,10 @@ static inline TVMArgs TVMArgs_Create(TVMValue * values, uint32_t * tcodes, uint3 static inline int TVMNoOperation(TVMValue * args, int * type_codes, int num_args, TVMRetValueHandle ret, void * res) { - return TVM_STATUS_SUCCESS; + return 0; } -// static inline int TVMNoOperation(void * args, int * type_codes, int num_args) { -// return TVM_STATUS_SUCCESS; -// } - typedef struct packed_func_t { - // Function (*GetFunction)(); char name[200]; TVMPackedCFunc fexec; TVMArgs args; @@ -147,7 +124,6 @@ void PackedFunc_SetupExecs(); // Put implementation in this file so we have seen the PackedFunc static inline void Module_GetFunction(const char * name, PackedFunc * pf) { int idx; - // PackedFunc pf; memset(pf, 0, sizeof(PackedFunc)); strcpy(pf->name, name); pf->Call = PackedFunc_Call; @@ -159,10 +135,9 @@ static inline void Module_GetFunction(const char * name, PackedFunc * pf) { break; } } - if (idx==GRAPH_RUNTIME_MAX_NODES) { - LOGE("function handle for %s not found", name); + if (idx == GRAPH_RUNTIME_MAX_NODES) { + fprintf(stderr, "function handle for %s not found\n", name); } - // return pf; } #endif // TVM_RUNTIME_PACKED_FUNC_H_ From cc49b177a9264f17423352352b8d094a1da58617 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Sat, 15 Feb 2020 23:15:48 +0800 Subject: [PATCH 11/31] clean up --- src/runtime/crt/c_backend_api.c | 1 - src/runtime/crt/graph_runtime.c | 3 ++- src/runtime/crt/graph_runtime.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c index 3dc608830107..714ce06e8b0e 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/c_backend_api.c @@ -55,5 +55,4 @@ int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_ta } int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { - // printf("TVMBackendRegisterSystemLibSymbol(%s) not implemented.\n", name); } diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 61f998709fc5..316cd76be281 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -21,9 +21,10 @@ * \file graph_runtime.c * \brief implement graph runtime in pure C */ -#include "graph_runtime.h" // #include +#include "graph_runtime.h" + #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif // MAX diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index d266336a387b..a1aa8844e773 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -26,10 +26,10 @@ #include -#include "load_json.h" // -#include "ndarray.h" // -#include "packed_func.h" // -#include "module.h" // +#include "load_json.h" +#include "ndarray.h" +#include "packed_func.h" +#include "module.h" /*! \brief macro to do C API call */ #define TVM_CCALL(func) \ From 8b34d2ee4e8356ee2c001c52c1c8e118599688aa Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Sat, 15 Feb 2020 23:58:07 +0800 Subject: [PATCH 12/31] satisfy linter --- include/tvm/runtime/crt/vm.h | 3 +- src/runtime/crt/c_backend_api.c | 7 +++- src/runtime/crt/graph_runtime.c | 58 ++++++++++++++++----------------- src/runtime/crt/graph_runtime.h | 47 +++++++++++++------------- src/runtime/crt/load_json.h | 28 ++++++++-------- src/runtime/crt/module.h | 6 ++-- src/runtime/crt/ndarray.h | 32 +++++++++--------- src/runtime/crt/packed_func.h | 10 +++--- 8 files changed, 99 insertions(+), 92 deletions(-) diff --git a/include/tvm/runtime/crt/vm.h b/include/tvm/runtime/crt/vm.h index f7f190b82679..99aec40a6052 100644 --- a/include/tvm/runtime/crt/vm.h +++ b/include/tvm/runtime/crt/vm.h @@ -24,6 +24,7 @@ #ifndef TVM_RUNTIME_CRT_VM_H_ #define TVM_RUNTIME_CRT_VM_H_ -/*! \brief Magic number for NDArray list file */ static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; +/*! \brief Magic number for NDArray list file */ +static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; #endif // TVM_RUNTIME_CRT_VM_H_ diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/c_backend_api.c index 714ce06e8b0e..f3e840122962 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/c_backend_api.c @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -44,7 +45,11 @@ int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) { } static char g_last_error[1024]; -void TVMAPISetLastError(const char* msg) { strcpy(g_last_error, msg); } + +void TVMAPISetLastError(const char* msg) { + snprintf(g_last_error, sizeof(g_last_error), "%s", msg); +} + const char* TVMGetLastError(void) { return g_last_error; } int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_task) { diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 316cd76be281..ce836fc27f7f 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -27,7 +27,7 @@ #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif // MAX +#endif // MAX static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { int64_t accum = 1; @@ -68,22 +68,23 @@ int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { void GraphRuntime_SetInput(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in) { uint32_t index = runtime->GetInputIndex(runtime, name); if (index >= runtime->input_nodes_count) { - fprintf(stderr, "given index is greater than num of input nodes."); + fprintf(stderr, "given index is greater than num of input nodes.\n"); } uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[index], 0); runtime->data_entry[eid].dl_tensor = *data_in; } -int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param_blob, const uint32_t param_size) { +int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param_blob, + const uint32_t param_size) { int status = 0; const char * bptr = param_blob; uint64_t header, reserved; - header = ((uint64_t*)bptr)[0]; + header = ((uint64_t*)bptr)[0]; // NOLINT(*) bptr += sizeof(header); if (header != kTVMNDArrayListMagic) { fprintf(stderr, "Invalid parameters file format"); } - reserved = ((uint64_t*)bptr)[0]; + reserved = ((uint64_t*)bptr)[0]; // NOLINT(*) bptr += sizeof(reserved); // read names @@ -91,14 +92,14 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param memset(names, 0, sizeof(names)); uint64_t names_count; int idx; - names_count = ((uint64_t*)bptr)[0]; + names_count = ((uint64_t*)bptr)[0]; // NOLINT(*) bptr += sizeof(names_count); for (idx = 0; idx < names_count; idx++) { uint64_t name_length; - name_length = ((uint64_t*)bptr)[0]; + name_length = ((uint64_t*)bptr)[0]; // NOLINT(*) bptr += sizeof(name_length); - if (name_length >= 80){ - fprintf(stderr, "Error: function name longer than expected."); + if (name_length >= 80) { + fprintf(stderr, "Error: function name longer than expected.\n"); } memcpy(names[idx], bptr, name_length); bptr += name_length; @@ -106,23 +107,24 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param // read sizes uint64_t sz; - sz = ((uint64_t*)bptr)[0]; + sz = ((uint64_t*)bptr)[0]; // NOLINT(*) bptr += sizeof(sz); uint32_t size = sz; if (size != names_count) { - fprintf(stderr, "Invalid parameters file format"); + fprintf(stderr, "Invalid parameters file format\n"); status = -1; } for (idx = 0; idx < size; idx++) { int32_t in_idx = runtime->GetInputIndex(runtime, names[idx]); if (!(in_idx >= 0)) { - fprintf(stderr, "Found param for non-existent input: %s", names[idx]); + fprintf(stderr, "Found param for non-existent input: %s\n", names[idx]); status = -1; } uint32_t eid = runtime->GetEntryId(runtime, runtime->input_nodes[in_idx], 0); if (!(eid < runtime->data_entry_count)) { - fprintf(stderr, "`entry_id`=%d is greater than expected(%d).", eid, runtime->data_entry_count); + fprintf(stderr, "`entry_id`=%d is greater than expected(%d).\n", + eid, runtime->data_entry_count); status = -1; } @@ -130,9 +132,9 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param #if TVM_CRT_DEBUG NDArray * entry = &(runtime->data_entry[eid]); printf("param %s loaded, in_idx=%d, eid=%d, ndim=%d, data[0]=%f\n", - names[idx], in_idx, eid, entry->dl_tensor.ndim, - ((float*)entry->dl_tensor.data)[0]); -#endif // TVM_CRT_DEBUG + names[idx], in_idx, eid, entry->dl_tensor.ndim, + ((float*)entry->dl_tensor.data)[0]); // NOLINT(*) +#endif // TVM_CRT_DEBUG } return status; @@ -148,7 +150,7 @@ void GraphRuntime_Run(GraphRuntime * runtime) { if (runtime->op_execs[idx].fexec) { #if TVM_CRT_DEBUG printf("calling %s (%d)\n", runtime->op_execs[idx].name, idx); -#endif // TVM_CRT_DEBUG +#endif // TVM_CRT_DEBUG runtime->op_execs[idx].Call(&(runtime->op_execs[idx])); } } @@ -206,7 +208,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { // Allocate the space. for (idx = 0; idx < pool_entry_count; idx++) { PoolEntry pit = pool_entry[idx]; - int64_t shape[TVM_CRT_MAX_NDIM] = {0,}; + int64_t shape[TVM_CRT_MAX_NDIM] = {0, }; TVMContext ctx = runtime->ctxs[0]; DLDataType dtype = {kDLFloat, 32, 1}; shape[0] = (pit.size + 3) / 4; @@ -225,7 +227,8 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { size_t storage_id = attrs->storage_id[idx]; assert(storage_id < runtime->storage_pool_count); runtime->data_entry[idx] = - NDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], attrs->ndim[idx], vtype[idx]); + NDArray_CreateView(&(runtime->storage_pool[storage_id]), + attrs->shape[idx], attrs->ndim[idx], vtype[idx]); if (runtime->data_entry[idx].dl_tensor.data == 0) { fprintf(stderr, "fail to create for node with idx=%d, storage_id=%d\n", idx, storage_id); } @@ -245,12 +248,12 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { const NodeEntry * entry = inode->inputs + idx; uint32_t eid = runtime->GetEntryId(runtime, entry->node_id, entry->index); args[idx] = &(runtime->data_entry[eid].dl_tensor); - args_count ++; + args_count++; } for (idx = 0; idx < inode->param.num_outputs; idx++) { uint32_t eid = runtime->GetEntryId(runtime, nid, idx); args[args_count] = &(runtime->data_entry[eid].dl_tensor); - args_count ++; + args_count++; } if (strcmp(inode->op_type, "tvm_op")) { fprintf(stderr, "Can only take tvm_op as op\n"); status = -1; @@ -264,7 +267,7 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { } #if TVM_CRT_DEBUG printf("creating tvm_op: %s with node_id=%d\n", inode->param.func_name, nid); -#endif // TVM_CRT_DEBUG +#endif // TVM_CRT_DEBUG PackedFunc pf; runtime->CreateTVMOp(runtime, &(inode->param), args, args_count, inode->inputs_count, &pf); runtime->op_execs[nid] = pf; @@ -290,10 +293,7 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para uint32_t idx; OpArgs arg_ptr; memset(&arg_ptr, 0, sizeof(OpArgs)); - for (idx = 0; idx < args_count; idx++) { - /* arg_ptr.args[idx] = args[idx]; */ - } - arg_ptr.args_count = args_count; + arg_ptr.args_count = args_count; if (param->flatten_data) { arg_ptr.shape_data_count = arg_ptr.args_count; } @@ -304,9 +304,9 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para /* v.v_handle = &((*args)[idx]); */ v.v_handle = args[idx]; arg_ptr.arg_values[idx] = v; - arg_ptr.arg_values_count ++; + arg_ptr.arg_values_count++; arg_ptr.arg_tcodes[idx] = kTVMNDArrayHandle; - arg_ptr.arg_tcodes_count ++; + arg_ptr.arg_tcodes_count++; if (param->flatten_data) { arg_ptr.shape_data[idx] = Shape_Accumulate(t->shape, t->ndim); t->ndim = 1; @@ -345,7 +345,7 @@ void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, const TVMContext * ctxs) { - GraphRuntime * runtime = (GraphRuntime*)malloc(sizeof(GraphRuntime)); + GraphRuntime * runtime = (GraphRuntime*)malloc(sizeof(GraphRuntime)); // NOLINT(*) memset(runtime, 0, sizeof(GraphRuntime)); runtime->GetEntryId = GraphRuntime_GetEntryId; runtime->GetInputIndex = GraphRuntime_GetInputIndex; diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index a1aa8844e773..65a9a7eb82eb 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -21,8 +21,8 @@ * \file graph_runtime.h * \brief Tiny graph runtime that can run graph containing only tvm PackedFunc. */ -#ifndef TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ -#define TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ +#ifndef TVM_RUNTIME_CRT_GRAPH_RUNTIME_H_ +#define TVM_RUNTIME_CRT_GRAPH_RUNTIME_H_ #include @@ -114,7 +114,7 @@ static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReade while (reader->NextObjectItem(reader, key)) { reader->ReadString(reader, value); if (!strcmp(key, "func_name")) { - strcpy(param->func_name, value); + snprintf(param->func_name, sizeof(value), "%s", value); bitmask |= 1; } else if (!strcmp(key, "num_inputs")) { param->num_inputs = strtoul(value, 0, 10); @@ -209,10 +209,10 @@ static inline GraphRuntimeNode GraphRuntimeNodeCreate() { // Graph attribute typedef struct graph_runtime_graph_attr_t { - uint32_t storage_num_not_alloctaed; // {0}; + uint32_t storage_num_not_alloctaed; uint32_t storage_id[GRAPH_RUNTIME_MAX_NODES]; uint32_t device_index[GRAPH_RUNTIME_MAX_NODES]; - char dltype[GRAPH_RUNTIME_MAX_NODES][10]; // "int8", "int16", "float32" + char dltype[GRAPH_RUNTIME_MAX_NODES][10]; // "int8", "int16", "float32" uint32_t dltype_count; int64_t shape[GRAPH_RUNTIME_MAX_NODES][TVM_CRT_MAX_NDIM]; uint32_t ndim[GRAPH_RUNTIME_MAX_NODES]; @@ -238,7 +238,7 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { reader->ReadString(reader, attr->dltype[dltype_count]); - dltype_count ++; + dltype_count++; } attr->dltype_count = dltype_count;; if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } @@ -269,15 +269,15 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR uint32_t ndim = 1; if (reader->NextArrayItem(reader)) { if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][1])); ndim ++; + reader->ReadInteger(reader, &(attr->shape[shape_count][1])); ndim++; if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][2])); ndim ++; + reader->ReadInteger(reader, &(attr->shape[shape_count][2])); ndim++; if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][3])); ndim ++; + reader->ReadInteger(reader, &(attr->shape[shape_count][3])); ndim++; if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][4])); ndim ++; + reader->ReadInteger(reader, &(attr->shape[shape_count][4])); ndim++; if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][5])); ndim ++; + reader->ReadInteger(reader, &(attr->shape[shape_count][5])); ndim++; reader->NextArrayItem(reader); } } @@ -286,7 +286,7 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR } } attr->ndim[shape_count] = ndim; - shape_count ++; + shape_count++; } attr->shape_count = shape_count; if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } @@ -299,7 +299,7 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } while (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(attr->device_index[device_index_count])); - device_index_count ++; + device_index_count++; } if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } } else { @@ -313,7 +313,7 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { reader->ReadUnsignedInteger(reader, &(temp[temp_count])); - temp_count ++; + temp_count++; } } else if (!strcmp(type, "size_t")) { if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } @@ -438,7 +438,6 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) int status = 0; reader->BeginObject(reader); int bitmask = 0; - /* String key = StringCreate(); */ char key[20]; while (reader->NextObjectItem(reader, key)) { if (!strcmp(key, "nodes")) { @@ -452,9 +451,9 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) #if TVM_CRT_DEBUG } else { printf("layer %u: `%s` loaded.\n", runtime->nodes_count, node->name); -#endif // TVM_CRT_DEBUG +#endif // TVM_CRT_DEBUG } - runtime->nodes_count ++; /* seq push */ + runtime->nodes_count++; } bitmask |= 1; } else if (!strcmp(key, "arg_nodes")) { @@ -462,7 +461,7 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) while (reader->NextArrayItem(reader)) { uint32_t * node = runtime->input_nodes + runtime->input_nodes_count; reader->ReadUnsignedInteger(reader, node); - runtime->input_nodes_count ++; + runtime->input_nodes_count++; } bitmask |= 2; } else if (!strcmp(key, "node_row_ptr")) { @@ -471,7 +470,7 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) uint32_t count = runtime->node_row_ptr_count; uint32_t * node = runtime->node_row_ptr + count; reader->ReadUnsignedInteger(reader, node); - runtime->node_row_ptr_count ++; + runtime->node_row_ptr_count++; } bitmask |= 4; } else if (!strcmp(key, "heads")) { @@ -480,23 +479,23 @@ static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) NodeEntry * entry = runtime->outputs + runtime->outputs_count; status = NodeEntry_Load(entry, reader); if (status != 0) { - fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node."); + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); break; } - runtime->outputs_count ++; /* seq push */ + runtime->outputs_count++; } bitmask |= 8; } else if (!strcmp(key, "attrs")) { status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); if (status != 0) { - fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node."); + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); break; } bitmask |= 16; } else if (!strcmp(key, "metadata")) { break; } else { - fprintf(stderr, "key %s is not supported", key); + fprintf(stderr, "key %s is not supported\n", key); status = -1; } if (status != 0) { break; } @@ -515,4 +514,4 @@ GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, void TVMGraphRuntimeRelease(GraphRuntime ** runtime); -#endif // TVM_RUNTIME_GRAPH_GRAPH_RUNTIME_H_ +#endif // TVM_RUNTIME_CRT_GRAPH_RUNTIME_H_ diff --git a/src/runtime/crt/load_json.h b/src/runtime/crt/load_json.h index fe4c100d3209..4dca9d9b1e1c 100644 --- a/src/runtime/crt/load_json.h +++ b/src/runtime/crt/load_json.h @@ -21,8 +21,8 @@ * \file load_json.h * \brief Lightweight JSON Reader that read save into C++ data structs. */ -#ifndef LOAD_JSON_H_ -#define LOAD_JSON_H_ +#ifndef TVM_RUNTIME_CRT_LOAD_JSON_H_ +#define TVM_RUNTIME_CRT_LOAD_JSON_H_ #include #include @@ -76,10 +76,10 @@ static inline void SeqPop(Seq * seq) { } static inline Seq * SeqCreate(uint64_t len) { - Seq * seq = (Seq*)malloc(sizeof(Seq)); + Seq * seq = (Seq*)malloc(sizeof(Seq)); // NOLINT(*) memset(seq, 0, sizeof(Seq)); seq->allocated = len; - seq->data = (uint32_t*)malloc(sizeof(uint32_t)*len); + seq->data = (uint32_t*)malloc(sizeof(uint32_t)*len); // NOLINT(*) seq->push_back = SeqPush; seq->back = SeqBack; seq->pop_back = SeqPop; @@ -247,12 +247,12 @@ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { if (ch == '\\') { char sch = reader->NextChar(reader); switch (sch) { - case 'r': strcat(output, "\r"); break; - case 'n': strcat(output, "\n"); break; - case '\\': strcat(output, "\\"); break; - case 't': strcat(output, "\t"); break; - case '\"': strcat(output, "\""); break; - default: fprintf(stderr, "unknown string escape \%c\n", sch); + case 'r': snprintf(output, sizeof(output), "%s\r", output); break; + case 'n': snprintf(output, sizeof(output), "%s\n", output); break; + case '\\': snprintf(output, sizeof(output), "%s\\", output); break; + case 't': snprintf(output, sizeof(output), "%s\t", output); break; + case '\"': snprintf(output, sizeof(output), "%s\"", output); break; + default: fprintf(stderr, "unknown string escape %c\n", sch); } } else { if (ch == '\"') { break; } @@ -273,7 +273,7 @@ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { fprintf(stderr, "Error at line X, Expect \'\"\' but reach end of line\n"); } } - strcpy(out_str, output); + snprintf(out_str, sizeof(output), "%s", output); return status; } @@ -437,9 +437,9 @@ static inline JSONReader JSONReader_Create(const char * is) { reader.BeginObject = JSONReader_BeginObject; reader.NextArrayItem = JSONReader_NextArrayItem; reader.NextObjectItem = JSONReader_NextObjectItem; - reader.is_ = (char*)malloc(strlen(is)+1); + reader.is_ = (char*)malloc(strlen(is)+1); // NOLINT(*) memset(reader.is_, 0, strlen(is)+1); - strcpy(reader.is_, is); + snprintf(reader.is_, strlen(is)+1, "%s", is); reader.isptr = reader.is_; return reader; } @@ -449,4 +449,4 @@ static inline void JSONReader_Release(JSONReader * reader) { free(reader->is_); } -#endif // LOAD_JSON_H_ +#endif // TVM_RUNTIME_CRT_LOAD_JSON_H_ diff --git a/src/runtime/crt/module.h b/src/runtime/crt/module.h index c622c519bbe2..517e2c4a1d1e 100644 --- a/src/runtime/crt/module.h +++ b/src/runtime/crt/module.h @@ -21,8 +21,8 @@ * \file src/runtime/crt/module.h * \brief Runtime container of the functions */ -#ifndef TVM_RUNTIME_MODULE_H_ -#define TVM_RUNTIME_MODULE_H_ +#ifndef TVM_RUNTIME_CRT_MODULE_H_ +#define TVM_RUNTIME_CRT_MODULE_H_ #include #include @@ -49,4 +49,4 @@ typedef struct module_t { void (*run)(const struct module_t * mod); } Module; -#endif // TVM_RUNTIME_MODULE_H_ +#endif // TVM_RUNTIME_CRT_MODULE_H_ diff --git a/src/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h index d178cb23eab0..98646f317372 100644 --- a/src/runtime/crt/ndarray.h +++ b/src/runtime/crt/ndarray.h @@ -21,8 +21,8 @@ * \file tvm/runtime/crt/ndarray.h * \brief Abstract device memory management API */ -#ifndef TVM_RUNTIME_NDARRAY_H_ -#define TVM_RUNTIME_NDARRAY_H_ +#ifndef TVM_RUNTIME_CRT_NDARRAY_H_ +#define TVM_RUNTIME_CRT_NDARRAY_H_ #include #include @@ -41,11 +41,12 @@ typedef struct ndarray_t { NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, uint32_t ndim, DLDataType dtype); -static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx) { +static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, + DLDataType dtype, DLContext ctx) { NDArray ret; memset(&ret, 0, sizeof(NDArray)); ret.dl_tensor.ndim = ndim; - ret.dl_tensor.shape = (int64_t*)malloc(sizeof(int64_t)*ndim); // TODO(liangfu): release memory + ret.dl_tensor.shape = (int64_t*)malloc(sizeof(int64_t)*ndim); // NOLINT(*) memcpy(ret.dl_tensor.shape, shape, sizeof(int64_t)*ndim); ret.dl_tensor.dtype = dtype; ret.dl_tensor.ctx = ctx; @@ -53,7 +54,8 @@ static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, DLDataType return ret; } -static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx) { +static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, + DLDataType dtype, DLContext ctx) { NDArray ret = NDArray_Create(ndim, shape, dtype, ctx); int64_t num_elems = 1; int elem_bytes = (dtype.bits + 7) / 8; @@ -69,18 +71,18 @@ static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType d static inline int NDArray_Load(NDArray * ret, const char ** strm) { int32_t status = 0; uint64_t header, reserved; - header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); + header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); // NOLINT(*) if (header != kTVMNDArrayMagic) { fprintf(stderr, "Invalid DLTensor file format\n"); status = -1; } - reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); + reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); // NOLINT(*) DLContext ctx; uint32_t ndim; DLDataType dtype; - ctx = ((DLContext*)*strm)[0]; *strm += sizeof(ctx); - ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); - dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); + ctx = ((DLContext*)*strm)[0]; *strm += sizeof(ctx); // NOLINT(*) + ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); // NOLINT(*) + dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); // NOLINT(*) if ((ndim <= 0) || (ndim > TVM_CRT_MAX_NDIM)) { fprintf(stderr, "Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); status = -1; @@ -89,11 +91,11 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { fprintf(stderr, "Invalid DLTensor context: can only save as CPU tensor\n"); status = -1; } - int64_t shape[TVM_CRT_MAX_NDIM]; // [ndim]; + int64_t shape[TVM_CRT_MAX_NDIM]; uint32_t idx; if (ndim != 0) { - for (idx = 0; idx < ndim; idx++){ - shape[idx] = ((int64_t*)*strm)[0]; *strm += sizeof(shape[idx]); + for (idx = 0; idx < ndim; idx++) { + shape[idx] = ((int64_t*)*strm)[0]; *strm += sizeof(shape[idx]); // NOLINT(*) } } *ret = NDArray_Empty(ndim, shape, dtype, ctx); @@ -103,7 +105,7 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { num_elems *= ret->dl_tensor.shape[idx]; } int64_t data_byte_size; - data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); + data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); // NOLINT(*) if (!(data_byte_size == num_elems * elem_bytes)) { fprintf(stderr, "invalid DLTensor file format: data_byte_size=%ld, " "while num_elems*elem_bytes=%ld\n", @@ -116,4 +118,4 @@ static inline int NDArray_Load(NDArray * ret, const char ** strm) { return status; } -#endif // TVM_RUNTIME_NDARRAY_H_ +#endif // TVM_RUNTIME_CRT_NDARRAY_H_ diff --git a/src/runtime/crt/packed_func.h b/src/runtime/crt/packed_func.h index a943f6b868f5..fd6383a8be4d 100644 --- a/src/runtime/crt/packed_func.h +++ b/src/runtime/crt/packed_func.h @@ -21,8 +21,8 @@ * \file tvm/runtime/packed_func.h * \brief Type-erased function used across TVM API. */ -#ifndef TVM_RUNTIME_PACKED_FUNC_H_ -#define TVM_RUNTIME_PACKED_FUNC_H_ +#ifndef TVM_RUNTIME_CRT_PACKED_FUNC_H_ +#define TVM_RUNTIME_CRT_PACKED_FUNC_H_ #include @@ -71,7 +71,7 @@ static inline DLDataType String2DLDataType(const char * s) { if (*xdelim == 'x') { t.lanes = (uint16_t)(strtoul(xdelim + 1, &endpt, 10)); } - if (!(endpt == s + strlen(s))){ + if (!(endpt == s + strlen(s))) { fprintf(stderr, "unknown type %s\n", s); } return t; @@ -125,7 +125,7 @@ void PackedFunc_SetupExecs(); static inline void Module_GetFunction(const char * name, PackedFunc * pf) { int idx; memset(pf, 0, sizeof(PackedFunc)); - strcpy(pf->name, name); + snprintf(pf->name, strlen(name), "%s", name); pf->Call = PackedFunc_Call; pf->SetArgs = PackedFunc_SetArgs; pf->fexec = &TVMNoOperation; @@ -140,4 +140,4 @@ static inline void Module_GetFunction(const char * name, PackedFunc * pf) { } } -#endif // TVM_RUNTIME_PACKED_FUNC_H_ +#endif // TVM_RUNTIME_CRT_PACKED_FUNC_H_ From 70c269bf0e54d1ad7bcd68f4b627cfc3623bb541 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Sun, 16 Feb 2020 00:07:07 +0800 Subject: [PATCH 13/31] clean up --- apps/bundle_deploy_c/build_model.py | 4 ---- apps/bundle_deploy_c/demo.cc | 3 ++- apps/bundle_deploy_c/runtime.c | 20 -------------------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index 54db5d67afea..63ae68a29b0b 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -66,15 +66,11 @@ def build_bridge(opts): f_bridge.write(" } while (0)\n") f_bridge.write("\n") for node in nodes: - # if node[-2:] in [str(_) for _ in range(21, 25)]: - # continue f_bridge.write("int %s(TVMValue * args, int * arg_type_ids, int num_args, TVMRetValueHandle ret, void * res);\n" % (node,)) f_bridge.write("\n") f_bridge.write("void PackedFunc_SetupExecs() {\n") f_bridge.write(" int32_t idx = 0;\n") for node in nodes: - # if node[-2:] in [str(_) for _ in range(21, 25)]: - # continue f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) f_bridge.write("}\n") diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc index fb8a2a2723ab..225e2037d526 100644 --- a/apps/bundle_deploy_c/demo.cc +++ b/apps/bundle_deploy_c/demo.cc @@ -84,7 +84,8 @@ int main(int argc, char **argv) { max_index = i; } } - printf("The maximum position in output vector is: %d, with max-value %f.\n", max_index, max_iter); + printf("The maximum position in output vector is: %d, with max-value %f.\n", + max_index, max_iter); getFunc(bundle, "tvm_runtime_destroy")(handle); dlclose(bundle); return 0; diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index f31c5a6058db..f52924f81083 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -20,26 +20,6 @@ #include #include #include -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ - -/* #include "../../src/runtime/c_runtime_api.cc" */ -/* #include "../../src/runtime/cpu_device_api.cc" */ -/* #include "../../src/runtime/workspace_pool.cc" */ -/* #include "../../src/runtime/library_module.cc" */ -/* #include "../../src/runtime/module.cc" */ -/* #include "../../src/runtime/registry.cc" */ -/* #include "../../src/runtime/file_util.cc" */ -/* #include "../../src/runtime/threading_backend.cc" */ -/* #include "../../src/runtime/thread_pool.cc" */ -/* #include "../../src/runtime/ndarray.cc" */ -/* #include "../../src/runtime/object.cc" */ -/* #include "../../src/runtime/system_library.cc" */ -/* #include "../../src/runtime/graph/graph_runtime.cc" */ #include "../../src/runtime/crt/c_backend_api.c" #include "../../src/runtime/crt/graph_runtime.c" From 8b407a8a31fc5318bc4954349f70bd7b6b5d8405 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 24 Feb 2020 21:59:29 +0800 Subject: [PATCH 14/31] test with the cat image --- apps/bundle_deploy_c/Makefile | 6 +++--- apps/bundle_deploy_c/build_model.py | 32 +++++++++++++++++++++++++++++ apps/bundle_deploy_c/demo.cc | 13 ++++++------ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index abdad38ae84b..6af557442db2 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -53,8 +53,8 @@ PKG_LDFLAGS = -pthread build_dir := build -test: $(build_dir)/demo $(build_dir)/bundle.so - $(build_dir)/demo $(build_dir)/bundle.so +test: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin + $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin $(build_dir)/demo: demo.cc @mkdir -p $(@D) @@ -68,7 +68,7 @@ $(build_dir)/graph.json.c: $(build_dir)/graph.json $(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ -$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/bridge.c: build_model.py +$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/bridge.c $(build_dir)/cat.bin: build_model.py python3 $< -o $(build_dir) # Build our bundle against the serialized bundle.c API, the runtime.cc API, and diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index 63ae68a29b0b..c0e267bf044b 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -74,6 +74,37 @@ def build_bridge(opts): f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) f_bridge.write("}\n") +def build_inputs(opts): + from tvm.contrib import download + from PIL import Image + import numpy as np + + build_dir = os.path.abspath(opts.out_dir) + + # Download ImageNet categories + categ_url = "https://github.com/uwsaml/web-data/raw/master/vta/models/synset.txt" + categ_fn = os.path.join(build_dir, "synset.txt") + download.download(categ_url, categ_fn) + synset = eval(open(categ_fn).read()) + + # Download test image + image_url = 'https://homes.cs.washington.edu/~moreau/media/vta/cat.jpg' + image_fn = os.path.join(build_dir, "cat.png") + download.download(image_url, image_fn) + image = Image.open(image_fn).resize((224, 224)) + + def transform_image(image): + image = np.array(image) - np.array([123., 117., 104.]) + image /= np.array([58.395, 57.12, 57.375]) + image = image.transpose((2, 0, 1)) + image = image[np.newaxis, :] + return image + + x = transform_image(image) + print('x', x.shape) + with open(os.path.join(build_dir, "cat.bin"), "wb") as fp: + fp.write(x.astype(np.float32).tobytes()) + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) @@ -83,3 +114,4 @@ def build_bridge(opts): build_module(opts) build_bridge(opts) + build_inputs(opts) diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc index 225e2037d526..a7684ca9ed86 100644 --- a/apps/bundle_deploy_c/demo.cc +++ b/apps/bundle_deploy_c/demo.cc @@ -34,21 +34,20 @@ template auto getFunc(void *bundle, const char *name) { } int main(int argc, char **argv) { - assert(argc == 2 && "Usage: demo "); + assert(argc == 3 && "Usage: demo "); auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); assert(bundle); auto *handle = getFunc(bundle, "tvm_runtime_create")(); - std::vector input_storage(1 * 3 * 224 * 224); - std::mt19937 gen(0); - for (auto &e : input_storage) { - e = std::uniform_real_distribution(0.0, 1.0)(gen); - } + float input_storage[1 * 3 * 224 * 224]; + FILE * fp = fopen(argv[2], "rb"); + fread(input_storage, 3 * 224 * 224, 4, fp); + fclose(fp); std::vector input_shape = {1, 3, 224, 224}; DLTensor input; - input.data = input_storage.data(); + input.data = input_storage; input.ctx = DLContext{kDLCPU, 0}; input.ndim = 4; input.dtype = DLDataType{kDLFloat, 32, 1}; From a9190338930236c6dde06a1847d8025c09a9ef98 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 24 Feb 2020 22:07:20 +0800 Subject: [PATCH 15/31] remove synset --- apps/bundle_deploy_c/build_model.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index c0e267bf044b..80f11f26bedd 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -81,12 +81,6 @@ def build_inputs(opts): build_dir = os.path.abspath(opts.out_dir) - # Download ImageNet categories - categ_url = "https://github.com/uwsaml/web-data/raw/master/vta/models/synset.txt" - categ_fn = os.path.join(build_dir, "synset.txt") - download.download(categ_url, categ_fn) - synset = eval(open(categ_fn).read()) - # Download test image image_url = 'https://homes.cs.washington.edu/~moreau/media/vta/cat.jpg' image_fn = os.path.join(build_dir, "cat.png") From 6183549128b57f302308272b9185d08d3c2b7db6 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 26 Feb 2020 15:06:20 +0800 Subject: [PATCH 16/31] refactoring --- apps/bundle_deploy_c/build_model.py | 2 +- include/tvm/runtime/crt/vm.h | 30 --- src/runtime/crt/bundle.c | 14 +- src/runtime/crt/graph_runtime.c | 395 +++++++++++++++++++++++++--- src/runtime/crt/graph_runtime.h | 380 +++----------------------- src/runtime/crt/load_json.c | 314 ++++++++++++++++++++++ src/runtime/crt/load_json.h | 393 ++------------------------- src/runtime/crt/module.h | 16 +- src/runtime/crt/ndarray.c | 82 +++++- src/runtime/crt/ndarray.h | 87 +----- src/runtime/crt/packed_func.h | 37 ++- 11 files changed, 836 insertions(+), 914 deletions(-) delete mode 100644 include/tvm/runtime/crt/vm.h diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index 80f11f26bedd..d60d144668da 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -68,7 +68,7 @@ def build_bridge(opts): for node in nodes: f_bridge.write("int %s(TVMValue * args, int * arg_type_ids, int num_args, TVMRetValueHandle ret, void * res);\n" % (node,)) f_bridge.write("\n") - f_bridge.write("void PackedFunc_SetupExecs() {\n") + f_bridge.write("void TVMPackedFunc_SetupExecs() {\n") f_bridge.write(" int32_t idx = 0;\n") for node in nodes: f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) diff --git a/include/tvm/runtime/crt/vm.h b/include/tvm/runtime/crt/vm.h deleted file mode 100644 index 99aec40a6052..000000000000 --- a/include/tvm/runtime/crt/vm.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/*! - * \file tvm/runtime/vm.h - * \brief A virtual machine for executing Relay programs. - */ -#ifndef TVM_RUNTIME_CRT_VM_H_ -#define TVM_RUNTIME_CRT_VM_H_ - -/*! \brief Magic number for NDArray list file */ -static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; - -#endif // TVM_RUNTIME_CRT_VM_H_ diff --git a/src/runtime/crt/bundle.c b/src/runtime/crt/bundle.c index ae8b9d5d4ce7..eb1b86bf69e3 100644 --- a/src/runtime/crt/bundle.c +++ b/src/runtime/crt/bundle.c @@ -24,9 +24,7 @@ extern unsigned int build_graph_json_len; extern unsigned char build_params_bin[]; extern unsigned int build_params_bin_len; -#define TVM_BUNDLE_FUNCTION __attribute__((visibility("default"))) - -TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { +TVM_DLL TVMGraphRuntime * tvm_runtime_create() { char * json_data = build_graph_json; int device_type = kDLCPU; @@ -39,27 +37,27 @@ TVM_BUNDLE_FUNCTION GraphRuntime * tvm_runtime_create() { TVMContext ctx; ctx.device_type = device_type; ctx.device_id = device_id; - GraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); + TVMGraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); runtime->LoadParams(runtime, params.data, params.size); return runtime; } -TVM_BUNDLE_FUNCTION void tvm_runtime_destroy(GraphRuntime * runtime) { +TVM_DLL void tvm_runtime_destroy(TVMGraphRuntime * runtime) { TVMGraphRuntimeRelease(&runtime); } -TVM_BUNDLE_FUNCTION void tvm_runtime_set_input(GraphRuntime * runtime, const char * name, +TVM_DLL void tvm_runtime_set_input(TVMGraphRuntime * runtime, const char * name, DLTensor * tensor) { runtime->SetInput(runtime, "data", tensor); } -TVM_BUNDLE_FUNCTION void tvm_runtime_run(GraphRuntime * runtime) { +TVM_DLL void tvm_runtime_run(TVMGraphRuntime * runtime) { runtime->Run(runtime); } -TVM_BUNDLE_FUNCTION void tvm_runtime_get_output(GraphRuntime * runtime, int32_t index, +TVM_DLL void tvm_runtime_get_output(TVMGraphRuntime * runtime, int32_t index, DLTensor * tensor) { runtime->GetOutput(runtime, index, tensor); } diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index ce836fc27f7f..551214e0eea3 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -21,8 +21,6 @@ * \file graph_runtime.c * \brief implement graph runtime in pure C */ -#include - #include "graph_runtime.h" #ifndef MAX @@ -39,12 +37,323 @@ static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { return accum; } +static inline int NodeEntry_Load(TVMGraphRuntimeNodeEntry * entry, JSONReader * reader) { + int status = 0; + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { + fprintf(stderr, "invalid json format: failed to parse `node_id`\n"); + } + reader->ReadUnsignedInteger(reader, &(entry->node_id)); + if (!(reader->NextArrayItem(reader))) { + fprintf(stderr, "invalid json format: failed to parse `index`\n"); + } + reader->ReadUnsignedInteger(reader, &(entry->index)); + if (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(entry->version)); + if (reader->NextArrayItem(reader)) { + fprintf(stderr, "invalid json format: failed to parse `version`\n"); + } + } else { + entry->version = 0; + } + return status; +} + +static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, + TVMOpParam* param) { + int bitmask = 0; + char key[20], value[120]; + memset(param, 0, sizeof(TVMOpParam)); + memset(key, 0, sizeof(key)); + memset(value, 0, sizeof(value)); + reader->BeginObject(reader); + while (reader->NextObjectItem(reader, key)) { + reader->ReadString(reader, value); + if (!strcmp(key, "func_name")) { + snprintf(param->func_name, sizeof(value), "%s", value); + bitmask |= 1; + } else if (!strcmp(key, "num_inputs")) { + param->num_inputs = strtoul(value, 0, 10); + bitmask |= 2; + } else if (!strcmp(key, "num_outputs")) { + param->num_outputs = strtoul(value, 0, 10); + bitmask |= 4; + } else if (!strcmp(key, "flatten_data")) { + param->flatten_data = strtoul(value, 0, 10); + bitmask |= 8; + } else { + fprintf(stderr, "do not support key %s", key); + } + } + if (bitmask != (1|2|4|8)) { fprintf(stderr, "invalid format\n"); } +} + +static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *reader) { + int status = 0; + reader->BeginObject(reader); + int bitmask = 0; + char key[20]; + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "op")) { + reader->ReadString(reader, node->op_type); + bitmask |= 1; + } else if (!strcmp(key, "name")) { + reader->ReadString(reader, node->name); + bitmask |= 2; + } else if (!strcmp(key, "inputs")) { + size_t count = node->inputs_count; + if (count >= GRAPH_RUNTIME_NODE_MAX_INPUTS) { + fprintf(stderr, "The number of inputs in graph runtime node is greater than expected.\n"); + status = -1; + break; + } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + TVMGraphRuntimeNodeEntry * inputs = node->inputs + count; + reader->BeginArray(reader); + if (!reader->NextArrayItem(reader)) { + fprintf(stderr, "invalid json format\n"); + status = -1; + break; + } + reader->ReadUnsignedInteger(reader, &(inputs->node_id)); + if (!reader->NextArrayItem(reader)) { + fprintf(stderr, "invalid json format\n"); + status = -1; + break; + } + reader->ReadUnsignedInteger(reader, &(inputs->index)); + if (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(inputs->version)); + if (reader->NextArrayItem(reader)) { + fprintf(stderr, "invalid json format\n"); + status = -1; + break; + } + } else { + inputs->version = 0; + } + count++; + } + node->inputs_count = count; + bitmask |= 4; + } else if (!strcmp(key, "attr") || !strcmp(key, "attrs")) { + TVMOpParam param; + + GraphRuntimeNode_LoadAttrs(node, reader, ¶m); + memcpy(&node->param, ¶m, sizeof(param)); + } else if (!strcmp(key, "control_deps")) { + fprintf(stderr, "do not support key %s", key); + status = -1; + } else { + fprintf(stderr, "do not support key %s", key); + status = -1; + } + if (status != 0) { break; } + } + if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } + return status; +} + +static inline GraphRuntimeNode GraphRuntimeNodeCreate() { + GraphRuntimeNode node; + memset(&node, 0, sizeof(GraphRuntimeNode)); + node.LoadAttrs = GraphRuntimeNode_LoadAttrs; + node.Load = GraphRuntimeNode_Load; + return node; +} + +static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONReader *reader) { + int status = 0; + int bitmask = 0; + char key[16], type[16]; + uint32_t storage_id_count = 0; + uint32_t dltype_count = 0; + uint32_t shape_count = 0; + uint32_t device_index_count = 0; + reader->BeginObject(reader); + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "dltype")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_str")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadString(reader, attr->dltype[dltype_count]); + dltype_count++; + } + attr->dltype_count = dltype_count;; + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } + bitmask |= 1; + } else if (!strcmp(key, "storage_id")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(attr->storage_id[storage_id_count])); + storage_id_count++; + } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } + bitmask |= 2; + } else if (!strcmp(key, "shape")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_shape")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->BeginArray(reader); + reader->ReadInteger(reader, &(attr->shape[shape_count][0])); + uint32_t ndim = 1; + if (reader->NextArrayItem(reader)) { + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][1])); ndim++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][2])); ndim++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][3])); ndim++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][4])); ndim++; + if (reader->NextArrayItem(reader)) { + reader->ReadInteger(reader, &(attr->shape[shape_count][5])); ndim++; + reader->NextArrayItem(reader); + } + } + } + } + } + } + attr->ndim[shape_count] = ndim; + shape_count++; + } + attr->shape_count = shape_count; + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } + bitmask |= 4; + } else if (!strcmp(key, "device_index")) { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->ReadString(reader, type); + if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(attr->device_index[device_index_count])); + device_index_count++; + } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } + } else { + reader->BeginArray(reader); + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + reader->ReadString(reader, type); + if (!strcmp(type, "list_int")) { + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + uint32_t temp[GRAPH_RUNTIME_MAX_NODES]; + uint32_t temp_count = 0; + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + reader->ReadUnsignedInteger(reader, &(temp[temp_count])); + temp_count++; + } + } else if (!strcmp(type, "size_t")) { + if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } + uint32_t temp; + reader->ReadUnsignedInteger(reader, &temp); + } else { + fprintf(stderr, "cannot skip graph attr %s", key); + } + if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } + } + } + if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } + return status; +} + +static inline int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *reader) { + int status = 0; + reader->BeginObject(reader); + int bitmask = 0; + char key[20]; + while (reader->NextObjectItem(reader, key)) { + if (!strcmp(key, "nodes")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + GraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; + status = GraphRuntimeNode_Load(node, reader); + if (status != 0) { + fprintf(stderr, "failed to load an element in `nodes` field in graph runtime node.\n"); + break; +#if TVM_CRT_DEBUG + } else { + printf("layer %u: `%s` loaded.\n", runtime->nodes_count, node->name); +#endif // TVM_CRT_DEBUG + } + runtime->nodes_count++; + } + bitmask |= 1; + } else if (!strcmp(key, "arg_nodes")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + uint32_t * node = runtime->input_nodes + runtime->input_nodes_count; + reader->ReadUnsignedInteger(reader, node); + runtime->input_nodes_count++; + } + bitmask |= 2; + } else if (!strcmp(key, "node_row_ptr")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + uint32_t count = runtime->node_row_ptr_count; + uint32_t * node = runtime->node_row_ptr + count; + reader->ReadUnsignedInteger(reader, node); + runtime->node_row_ptr_count++; + } + bitmask |= 4; + } else if (!strcmp(key, "heads")) { + reader->BeginArray(reader); + while (reader->NextArrayItem(reader)) { + TVMGraphRuntimeNodeEntry * entry = runtime->outputs + runtime->outputs_count; + status = NodeEntry_Load(entry, reader); + if (status != 0) { + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); + break; + } + runtime->outputs_count++; + } + bitmask |= 8; + } else if (!strcmp(key, "attrs")) { + status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); + if (status != 0) { + fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); + break; + } + bitmask |= 16; + } else if (!strcmp(key, "metadata")) { + break; + } else { + fprintf(stderr, "key %s is not supported\n", key); + status = -1; + } + if (status != 0) { break; } + } + if (!(bitmask == (1|2|4|8|16))) { fprintf(stderr, "invalid format\n"); } + return status; +} + +static inline uint32_t TVMGraphRuntime_GetEntryId(TVMGraphRuntime * runtime, + uint32_t nid, uint32_t index) { + return runtime->node_row_ptr[nid] + index; +} + /*! * \brief Get the input index given the name of input. * \param name The name of the input. * \return The index of input. */ -int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { +int TVMGraphRuntime_GetInputIndex(TVMGraphRuntime * runtime, const char * name) { uint32_t i; int32_t rv = -1; for (i = 0; i< runtime->input_nodes_count; ++i) { @@ -65,7 +374,7 @@ int GraphRuntime_GetInputIndex(GraphRuntime * runtime, const char * name) { * \param index The input index. * \param data_in The input data. */ -void GraphRuntime_SetInput(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in) { +void TVMGraphRuntime_SetInput(TVMGraphRuntime * runtime, const char * name, DLTensor* data_in) { uint32_t index = runtime->GetInputIndex(runtime, name); if (index >= runtime->input_nodes_count) { fprintf(stderr, "given index is greater than num of input nodes.\n"); @@ -74,8 +383,8 @@ void GraphRuntime_SetInput(struct graph_runtime_t * runtime, const char * name, runtime->data_entry[eid].dl_tensor = *data_in; } -int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param_blob, - const uint32_t param_size) { +int TVMGraphRuntime_LoadParams(TVMGraphRuntime * runtime, const char * param_blob, + const uint32_t param_size) { int status = 0; const char * bptr = param_blob; uint64_t header, reserved; @@ -128,9 +437,9 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param status = -1; } - status |= NDArray_Load(&(runtime->data_entry[eid]), &bptr); + status |= TVMNDArray_Load(&(runtime->data_entry[eid]), &bptr); #if TVM_CRT_DEBUG - NDArray * entry = &(runtime->data_entry[eid]); + TVMNDArray * entry = &(runtime->data_entry[eid]); printf("param %s loaded, in_idx=%d, eid=%d, ndim=%d, data[0]=%f\n", names[idx], in_idx, eid, entry->dl_tensor.ndim, ((float*)entry->dl_tensor.data)[0]); // NOLINT(*) @@ -143,7 +452,7 @@ int GraphRuntime_LoadParams(struct graph_runtime_t * runtime, const char * param /*! * \brief Run all the operations one by one. */ -void GraphRuntime_Run(GraphRuntime * runtime) { +void TVMGraphRuntime_Run(TVMGraphRuntime * runtime) { // setup the array and requirements. uint32_t idx; for (idx = 0; idx < runtime->op_execs_count; ++idx) { @@ -156,7 +465,7 @@ void GraphRuntime_Run(GraphRuntime * runtime) { } } -int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * out) { +int TVMGraphRuntime_GetOutput(TVMGraphRuntime * runtime, const int32_t idx, DLTensor * out) { int status = 0; uint32_t nid = runtime->outputs[idx].node_id; uint32_t index = runtime->outputs[idx].index; @@ -173,7 +482,7 @@ int GraphRuntime_GetOutput(GraphRuntime * runtime, const int32_t idx, DLTensor * return status; } -void GraphRuntime_SetupStorage(GraphRuntime * runtime) { +void TVMGraphRuntime_SetupStorage(TVMGraphRuntime * runtime) { uint32_t idx, dim; // Grab saved optimization plan from graph. @@ -184,7 +493,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { } // Size and device type of each storage pool entry. - PoolEntry pool_entry[GRAPH_RUNTIME_MAX_NODES]; + TVMGraphRuntimePoolEntry pool_entry[GRAPH_RUNTIME_MAX_NODES]; memset(pool_entry, 0, sizeof(pool_entry)); uint32_t pool_entry_count = 0; // Find the maximum space size. @@ -207,12 +516,12 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { // Allocate the space. for (idx = 0; idx < pool_entry_count; idx++) { - PoolEntry pit = pool_entry[idx]; + TVMGraphRuntimePoolEntry pit = pool_entry[idx]; int64_t shape[TVM_CRT_MAX_NDIM] = {0, }; TVMContext ctx = runtime->ctxs[0]; DLDataType dtype = {kDLFloat, 32, 1}; shape[0] = (pit.size + 3) / 4; - runtime->storage_pool[runtime->storage_pool_count] = NDArray_Empty(1, shape, dtype, ctx); + runtime->storage_pool[runtime->storage_pool_count] = TVMNDArray_Empty(1, shape, dtype, ctx); if (runtime->storage_pool[runtime->storage_pool_count].dl_tensor.data == 0) { fprintf(stderr, "fail to create storage_pool with idx=%d\n", idx); } @@ -227,7 +536,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { size_t storage_id = attrs->storage_id[idx]; assert(storage_id < runtime->storage_pool_count); runtime->data_entry[idx] = - NDArray_CreateView(&(runtime->storage_pool[storage_id]), + TVMNDArray_CreateView(&(runtime->storage_pool[storage_id]), attrs->shape[idx], attrs->ndim[idx], vtype[idx]); if (runtime->data_entry[idx].dl_tensor.data == 0) { fprintf(stderr, "fail to create for node with idx=%d, storage_id=%d\n", idx, storage_id); @@ -235,7 +544,7 @@ void GraphRuntime_SetupStorage(GraphRuntime * runtime) { } } -int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { +int TVMGraphRuntime_SetupOpExecs(TVMGraphRuntime * runtime) { int status = 0; uint32_t nid, idx; runtime->op_execs_count = runtime->nodes_count; @@ -245,7 +554,7 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { DLTensorPtr args[GRAPH_RUNTIME_MAX_NODES]; uint32_t args_count = 0; for (idx = 0; idx < inode->inputs_count; idx++) { - const NodeEntry * entry = inode->inputs + idx; + const TVMGraphRuntimeNodeEntry * entry = inode->inputs + idx; uint32_t eid = runtime->GetEntryId(runtime, entry->node_id, entry->index); args[idx] = &(runtime->data_entry[eid].dl_tensor); args_count++; @@ -268,7 +577,7 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { #if TVM_CRT_DEBUG printf("creating tvm_op: %s with node_id=%d\n", inode->param.func_name, nid); #endif // TVM_CRT_DEBUG - PackedFunc pf; + TVMPackedFunc pf; runtime->CreateTVMOp(runtime, &(inode->param), args, args_count, inode->inputs_count, &pf); runtime->op_execs[nid] = pf; } @@ -276,7 +585,7 @@ int GraphRuntime_SetupOpExecs(GraphRuntime * runtime) { return status; } -typedef struct opargs_t { +typedef struct OpArgs { DLTensor args[TVM_CRT_MAX_ARGS]; uint32_t args_count; TVMValue arg_values[TVM_CRT_MAX_ARGS]; @@ -287,9 +596,9 @@ typedef struct opargs_t { uint32_t shape_data_count; } OpArgs; -int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * param, - DLTensorPtr * args, const uint32_t args_count, - uint32_t num_inputs, PackedFunc * pf) { +int32_t TVMGraphRuntime_CreateTVMOp(TVMGraphRuntime * runtime, const TVMOpParam * param, + DLTensorPtr * args, const uint32_t args_count, + uint32_t num_inputs, TVMPackedFunc * pf) { uint32_t idx; OpArgs arg_ptr; memset(&arg_ptr, 0, sizeof(OpArgs)); @@ -332,41 +641,41 @@ int32_t GraphRuntime_CreateTVMOp(GraphRuntime * runtime, const TVMOpParam * para * \param ctxs The context of the host and devices where graph nodes will be * executed on. */ -void GraphRuntime_Init(GraphRuntime * runtime, const char * graph_json, - const Module * module, const TVMContext * ctxs) { +void TVMGraphRuntime_Init(TVMGraphRuntime * runtime, const char * graph_json, + const TVMModule * module, const TVMContext * ctxs) { JSONReader reader = JSONReader_Create(graph_json); runtime->Load(runtime, &reader); runtime->ctxs[0] = ctxs[0]; runtime->SetupStorage(runtime); - PackedFunc_SetupExecs(); + TVMPackedFunc_SetupExecs(); runtime->SetupOpExecs(runtime); JSONReader_Release(&reader); } -GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, - const Module * m, const TVMContext * ctxs) { - GraphRuntime * runtime = (GraphRuntime*)malloc(sizeof(GraphRuntime)); // NOLINT(*) - memset(runtime, 0, sizeof(GraphRuntime)); - runtime->GetEntryId = GraphRuntime_GetEntryId; - runtime->GetInputIndex = GraphRuntime_GetInputIndex; - runtime->Init = GraphRuntime_Init; - runtime->Load = GraphRuntime_Load; - runtime->SetInput = GraphRuntime_SetInput; - runtime->LoadParams = GraphRuntime_LoadParams; - runtime->Run = GraphRuntime_Run; - runtime->GetOutput = GraphRuntime_GetOutput; - runtime->SetupStorage = GraphRuntime_SetupStorage; - runtime->SetupOpExecs = GraphRuntime_SetupOpExecs; - runtime->CreateTVMOp = GraphRuntime_CreateTVMOp; - runtime->module.GetFunction = Module_GetFunction; +TVMGraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, + const TVMModule * m, const TVMContext * ctxs) { + TVMGraphRuntime * runtime = (TVMGraphRuntime*)malloc(sizeof(TVMGraphRuntime)); // NOLINT(*) + memset(runtime, 0, sizeof(TVMGraphRuntime)); + runtime->GetEntryId = TVMGraphRuntime_GetEntryId; + runtime->GetInputIndex = TVMGraphRuntime_GetInputIndex; + runtime->Init = TVMGraphRuntime_Init; + runtime->Load = TVMGraphRuntime_Load; + runtime->SetInput = TVMGraphRuntime_SetInput; + runtime->LoadParams = TVMGraphRuntime_LoadParams; + runtime->Run = TVMGraphRuntime_Run; + runtime->GetOutput = TVMGraphRuntime_GetOutput; + runtime->SetupStorage = TVMGraphRuntime_SetupStorage; + runtime->SetupOpExecs = TVMGraphRuntime_SetupOpExecs; + runtime->CreateTVMOp = TVMGraphRuntime_CreateTVMOp; + runtime->module.GetFunction = TVMModule_GetFunction; // init runtime->Init(runtime, sym_json, m, ctxs); return runtime; } -void TVMGraphRuntimeRelease(GraphRuntime ** pptr) { +void TVMGraphRuntimeRelease(TVMGraphRuntime ** pptr) { int32_t idx; - GraphRuntime * runtime = *pptr; + TVMGraphRuntime * runtime = *pptr; for (idx = 0; idx < runtime->storage_pool_count; ++idx) { free(runtime->storage_pool[idx].dl_tensor.data); free(runtime->storage_pool[idx].dl_tensor.shape); diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index 65a9a7eb82eb..ee03ce56a3dd 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -31,16 +31,8 @@ #include "packed_func.h" #include "module.h" -/*! \brief macro to do C API call */ -#define TVM_CCALL(func) \ - { \ - int ret = (func); \ - CHECK_EQ(ret, 0) \ - << TVMGetLastError(); \ - } - /*! \brief operator attributes about tvm op */ -typedef struct tvm_op_param_t { +typedef struct TVMOpParam { char func_name[120]; uint32_t num_inputs; uint32_t num_outputs; @@ -48,41 +40,19 @@ typedef struct tvm_op_param_t { } TVMOpParam; // Memory pool entry. -typedef struct graph_runtime_pool_entry_t { +typedef struct TVMGraphRuntimePoolEntry { size_t size; int device_type; -} PoolEntry; +} TVMGraphRuntimePoolEntry; // Node entry -typedef struct graph_runtime_node_entry_t { +typedef struct TVMGraphRuntimeNodeEntry { uint32_t node_id; uint32_t index; uint32_t version; // JSON Loader void (*Load)(JSONReader *reader); -} NodeEntry; - -static inline int NodeEntry_Load(NodeEntry * entry, JSONReader * reader) { - int status = 0; - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { - fprintf(stderr, "invalid json format: failed to parse `node_id`\n"); - } - reader->ReadUnsignedInteger(reader, &(entry->node_id)); - if (!(reader->NextArrayItem(reader))) { - fprintf(stderr, "invalid json format: failed to parse `index`\n"); - } - reader->ReadUnsignedInteger(reader, &(entry->index)); - if (reader->NextArrayItem(reader)) { - reader->ReadUnsignedInteger(reader, &(entry->version)); - if (reader->NextArrayItem(reader)) { - fprintf(stderr, "invalid json format: failed to parse `version`\n"); - } - } else { - entry->version = 0; - } - return status; -} +} TVMGraphRuntimeNodeEntry; // Node typedef struct graph_runtime_node_t { @@ -93,8 +63,8 @@ typedef struct graph_runtime_node_t { // parameters TVMOpParam param; // inputs - NodeEntry inputs[GRAPH_RUNTIME_NODE_MAX_INPUTS]; - size_t inputs_count; + TVMGraphRuntimeNodeEntry inputs[GRAPH_RUNTIME_NODE_MAX_INPUTS]; + size_t inputs_count; // control deps uint32_t control_deps[200]; // JSON Loader @@ -103,110 +73,6 @@ typedef struct graph_runtime_node_t { int (*Load)(struct graph_runtime_node_t * node, JSONReader *reader); } GraphRuntimeNode; -static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, - TVMOpParam* param) { - int bitmask = 0; - char key[20], value[120]; - memset(param, 0, sizeof(TVMOpParam)); - memset(key, 0, sizeof(key)); - memset(value, 0, sizeof(value)); - reader->BeginObject(reader); - while (reader->NextObjectItem(reader, key)) { - reader->ReadString(reader, value); - if (!strcmp(key, "func_name")) { - snprintf(param->func_name, sizeof(value), "%s", value); - bitmask |= 1; - } else if (!strcmp(key, "num_inputs")) { - param->num_inputs = strtoul(value, 0, 10); - bitmask |= 2; - } else if (!strcmp(key, "num_outputs")) { - param->num_outputs = strtoul(value, 0, 10); - bitmask |= 4; - } else if (!strcmp(key, "flatten_data")) { - param->flatten_data = strtoul(value, 0, 10); - bitmask |= 8; - } else { - fprintf(stderr, "do not support key %s", key); - } - } - if (bitmask != (1|2|4|8)) { fprintf(stderr, "invalid format\n"); } -} - -static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *reader) { - int status = 0; - reader->BeginObject(reader); - int bitmask = 0; - char key[20]; - while (reader->NextObjectItem(reader, key)) { - if (!strcmp(key, "op")) { - reader->ReadString(reader, node->op_type); - bitmask |= 1; - } else if (!strcmp(key, "name")) { - reader->ReadString(reader, node->name); - bitmask |= 2; - } else if (!strcmp(key, "inputs")) { - size_t count = node->inputs_count; - if (count >= GRAPH_RUNTIME_NODE_MAX_INPUTS) { - fprintf(stderr, "The number of inputs in graph runtime node is greater than expected.\n"); - status = -1; - break; - } - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - NodeEntry * inputs = node->inputs + count; - reader->BeginArray(reader); - if (!reader->NextArrayItem(reader)) { - fprintf(stderr, "invalid json format\n"); - status = -1; - break; - } - reader->ReadUnsignedInteger(reader, &(inputs->node_id)); - if (!reader->NextArrayItem(reader)) { - fprintf(stderr, "invalid json format\n"); - status = -1; - break; - } - reader->ReadUnsignedInteger(reader, &(inputs->index)); - if (reader->NextArrayItem(reader)) { - reader->ReadUnsignedInteger(reader, &(inputs->version)); - if (reader->NextArrayItem(reader)) { - fprintf(stderr, "invalid json format\n"); - status = -1; - break; - } - } else { - inputs->version = 0; - } - count++; - } - node->inputs_count = count; - bitmask |= 4; - } else if (!strcmp(key, "attr") || !strcmp(key, "attrs")) { - TVMOpParam param; - - GraphRuntimeNode_LoadAttrs(node, reader, ¶m); - memcpy(&node->param, ¶m, sizeof(param)); - } else if (!strcmp(key, "control_deps")) { - fprintf(stderr, "do not support key %s", key); - status = -1; - } else { - fprintf(stderr, "do not support key %s", key); - status = -1; - } - if (status != 0) { break; } - } - if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } - return status; -} - -static inline GraphRuntimeNode GraphRuntimeNodeCreate() { - GraphRuntimeNode node; - memset(&node, 0, sizeof(GraphRuntimeNode)); - node.LoadAttrs = GraphRuntimeNode_LoadAttrs; - node.Load = GraphRuntimeNode_Load; - return node; -} - // Graph attribute typedef struct graph_runtime_graph_attr_t { uint32_t storage_num_not_alloctaed; @@ -219,117 +85,6 @@ typedef struct graph_runtime_graph_attr_t { uint32_t shape_count; } GraphRuntimeGraphAttr; -static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONReader *reader) { - int status = 0; - int bitmask = 0; - char key[16], type[16]; - uint32_t storage_id_count = 0; - uint32_t dltype_count = 0; - uint32_t shape_count = 0; - uint32_t device_index_count = 0; - reader->BeginObject(reader); - while (reader->NextObjectItem(reader, key)) { - if (!strcmp(key, "dltype")) { - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->ReadString(reader, type); - if (strcmp(type, "list_str")) { fprintf(stderr, "Invalid json format\n"); } - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - reader->ReadString(reader, attr->dltype[dltype_count]); - dltype_count++; - } - attr->dltype_count = dltype_count;; - if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } - bitmask |= 1; - } else if (!strcmp(key, "storage_id")) { - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->ReadString(reader, type); - if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - reader->ReadUnsignedInteger(reader, &(attr->storage_id[storage_id_count])); - storage_id_count++; - } - if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } - bitmask |= 2; - } else if (!strcmp(key, "shape")) { - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->ReadString(reader, type); - if (strcmp(type, "list_shape")) { fprintf(stderr, "Invalid json format\n"); } - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - reader->BeginArray(reader); - reader->ReadInteger(reader, &(attr->shape[shape_count][0])); - uint32_t ndim = 1; - if (reader->NextArrayItem(reader)) { - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][1])); ndim++; - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][2])); ndim++; - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][3])); ndim++; - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][4])); ndim++; - if (reader->NextArrayItem(reader)) { - reader->ReadInteger(reader, &(attr->shape[shape_count][5])); ndim++; - reader->NextArrayItem(reader); - } - } - } - } - } - } - attr->ndim[shape_count] = ndim; - shape_count++; - } - attr->shape_count = shape_count; - if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } - bitmask |= 4; - } else if (!strcmp(key, "device_index")) { - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->ReadString(reader, type); - if (strcmp(type, "list_int")) { fprintf(stderr, "Invalid json format\n"); } - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - while (reader->NextArrayItem(reader)) { - reader->ReadUnsignedInteger(reader, &(attr->device_index[device_index_count])); - device_index_count++; - } - if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } - } else { - reader->BeginArray(reader); - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - reader->ReadString(reader, type); - if (!strcmp(type, "list_int")) { - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - uint32_t temp[GRAPH_RUNTIME_MAX_NODES]; - uint32_t temp_count = 0; - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - reader->ReadUnsignedInteger(reader, &(temp[temp_count])); - temp_count++; - } - } else if (!strcmp(type, "size_t")) { - if (!(reader->NextArrayItem(reader))) { fprintf(stderr, "Invalid json format\n"); } - uint32_t temp; - reader->ReadUnsignedInteger(reader, &temp); - } else { - fprintf(stderr, "cannot skip graph attr %s", key); - } - if (reader->NextArrayItem(reader)) { fprintf(stderr, "Invalid json format\n"); } - } - } - if (bitmask != (1|2|4)) { fprintf(stderr, "invalid format\n"); } - return status; -} - - typedef DLTensor* DLTensorPtr; /*! @@ -339,8 +94,8 @@ typedef DLTensor* DLTensorPtr; * TVM runtime PackedFunc API. */ /* class GraphRuntime : public ModuleNode { */ -typedef struct graph_runtime_t { - void (*Run)(struct graph_runtime_t * runtime); +typedef struct TVMGraphRuntime { + void (*Run)(struct TVMGraphRuntime * runtime); /*! * \brief Initialize the graph executor with graph and context. @@ -350,9 +105,9 @@ typedef struct graph_runtime_t { * \param ctxs The context of the host and devices where graph nodes will be * executed on. */ - void (*Init)(struct graph_runtime_t * runtime, + void (*Init)(struct TVMGraphRuntime * runtime, const char * graph_json, - const Module * module, + const TVMModule * module, const TVMContext * ctxs); /*! @@ -360,34 +115,34 @@ typedef struct graph_runtime_t { * \param name The name of the input. * \return The index of input. */ - int (*GetInputIndex)(struct graph_runtime_t * runtime, const char * name); + int (*GetInputIndex)(struct TVMGraphRuntime * runtime, const char * name); /*! * \brief set index-th input to the graph. * \param index The input index. * \param data_in The input data. */ - void (*SetInput)(struct graph_runtime_t * runtime, const char * name, DLTensor* data_in); + void (*SetInput)(struct TVMGraphRuntime * runtime, const char * name, DLTensor* data_in); /*! * \brief Return NDArray for given output index. * \param index The output index. * * \return NDArray corresponding to given output node index. */ - int (*GetOutput)(struct graph_runtime_t * runtime, const int32_t index, DLTensor * out); + int (*GetOutput)(struct TVMGraphRuntime * runtime, const int32_t index, DLTensor * out); /*! * \brief Load parameters from parameter blob. * \param param_blob A binary blob of parameter. */ - int (*LoadParams)(struct graph_runtime_t * runtime, const char * param_blob, + int (*LoadParams)(struct TVMGraphRuntime * runtime, const char * param_blob, const uint32_t param_size); // The graph attribute fields. - int (*Load)(struct graph_runtime_t * runtime, JSONReader *reader); + int (*Load)(struct TVMGraphRuntime * runtime, JSONReader *reader); /*! \brief Setup the temporal storage */ - void (*SetupStorage)(struct graph_runtime_t * runtime); + void (*SetupStorage)(struct TVMGraphRuntime * runtime); /*! \brief Setup the executors. */ - int (*SetupOpExecs)(struct graph_runtime_t * runtime); + int (*SetupOpExecs)(struct TVMGraphRuntime * runtime); /*! * \brief Create an execution function given input. @@ -396,12 +151,12 @@ typedef struct graph_runtime_t { * \param num_inputs Number of inputs. * \return The created executor. */ - int32_t (*CreateTVMOp)(struct graph_runtime_t * runtime, const TVMOpParam * attrs, + int32_t (*CreateTVMOp)(struct TVMGraphRuntime * runtime, const TVMOpParam * attrs, DLTensorPtr * args, const uint32_t args_count, - uint32_t num_inputs, PackedFunc * pf); + uint32_t num_inputs, TVMPackedFunc * pf); // Get node entry index. - uint32_t (*GetEntryId)(struct graph_runtime_t * runtime, uint32_t nid, uint32_t index); + uint32_t (*GetEntryId)(struct TVMGraphRuntime * runtime, uint32_t nid, uint32_t index); // /*! \brief The graph nodes. */ /* GraphRuntimeNode nodes_[GRAPH_RUNTIME_MAX_NODES]; */ @@ -414,104 +169,29 @@ typedef struct graph_runtime_t { uint32_t node_row_ptr[GRAPH_RUNTIME_MAX_NODE_ROW_PTR]; uint32_t node_row_ptr_count; /*! \brief Output entries. */ - NodeEntry outputs[GRAPH_RUNTIME_MAX_OUTPUTS]; + TVMGraphRuntimeNodeEntry outputs[GRAPH_RUNTIME_MAX_OUTPUTS]; uint32_t outputs_count; /*! \brief Additional graph attributes. */ GraphRuntimeGraphAttr attrs; /*! \brief The code module that contains both host and device code. */ - Module module; + TVMModule module; /*! \brief Execution context of all devices including the host. */ TVMContext ctxs[GRAPH_RUNTIME_MAX_CONTEXTS]; uint32_t ctxs_count; /*! \brief Common storage pool for all devices. */ - NDArray storage_pool[GRAPH_RUNTIME_MAX_NODES]; + TVMNDArray storage_pool[GRAPH_RUNTIME_MAX_NODES]; uint32_t storage_pool_count; /*! \brief Data entry of each node. */ - NDArray data_entry[GRAPH_RUNTIME_MAX_NODES]; + TVMNDArray data_entry[GRAPH_RUNTIME_MAX_NODES]; uint32_t data_entry_count; /*! \brief Operator on each node. */ - PackedFunc op_execs[GRAPH_RUNTIME_MAX_NODES]; + TVMPackedFunc op_execs[GRAPH_RUNTIME_MAX_NODES]; uint32_t op_execs_count; -} GraphRuntime; - -static inline int GraphRuntime_Load(GraphRuntime * runtime, JSONReader *reader) { - int status = 0; - reader->BeginObject(reader); - int bitmask = 0; - char key[20]; - while (reader->NextObjectItem(reader, key)) { - if (!strcmp(key, "nodes")) { - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - GraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; - status = GraphRuntimeNode_Load(node, reader); - if (status != 0) { - fprintf(stderr, "failed to load an element in `nodes` field in graph runtime node.\n"); - break; -#if TVM_CRT_DEBUG - } else { - printf("layer %u: `%s` loaded.\n", runtime->nodes_count, node->name); -#endif // TVM_CRT_DEBUG - } - runtime->nodes_count++; - } - bitmask |= 1; - } else if (!strcmp(key, "arg_nodes")) { - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - uint32_t * node = runtime->input_nodes + runtime->input_nodes_count; - reader->ReadUnsignedInteger(reader, node); - runtime->input_nodes_count++; - } - bitmask |= 2; - } else if (!strcmp(key, "node_row_ptr")) { - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - uint32_t count = runtime->node_row_ptr_count; - uint32_t * node = runtime->node_row_ptr + count; - reader->ReadUnsignedInteger(reader, node); - runtime->node_row_ptr_count++; - } - bitmask |= 4; - } else if (!strcmp(key, "heads")) { - reader->BeginArray(reader); - while (reader->NextArrayItem(reader)) { - NodeEntry * entry = runtime->outputs + runtime->outputs_count; - status = NodeEntry_Load(entry, reader); - if (status != 0) { - fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); - break; - } - runtime->outputs_count++; - } - bitmask |= 8; - } else if (!strcmp(key, "attrs")) { - status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); - if (status != 0) { - fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); - break; - } - bitmask |= 16; - } else if (!strcmp(key, "metadata")) { - break; - } else { - fprintf(stderr, "key %s is not supported\n", key); - status = -1; - } - if (status != 0) { break; } - } - if (!(bitmask == (1|2|4|8|16))) { fprintf(stderr, "invalid format\n"); } - return status; -} - -static inline uint32_t GraphRuntime_GetEntryId(GraphRuntime * runtime, - uint32_t nid, uint32_t index) { - return runtime->node_row_ptr[nid] + index; -} +} TVMGraphRuntime; -GraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const Module * m, - const TVMContext * ctxs); +TVMGraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const TVMModule * m, + const TVMContext * ctxs); -void TVMGraphRuntimeRelease(GraphRuntime ** runtime); +void TVMGraphRuntimeRelease(TVMGraphRuntime ** runtime); #endif // TVM_RUNTIME_CRT_GRAPH_RUNTIME_H_ diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index cd85607bcf65..42ae4460821c 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -44,3 +44,317 @@ void JSONNodeEntryLoad(JSONNodeEntry * entry, JSONReader *reader) { entry->version = 0; } } + + +// implementation of Seq class + + +static inline void SeqPush(Seq * seq, uint32_t src) { + if (seq->size >= seq->allocated) { + printf("seq too large.\n"); + } + seq->data[seq->size] = src; + seq->size += 1; +} + +static inline uint32_t * SeqBack(Seq * seq) { + if (seq->size >= seq->allocated) { + printf("seq too large.\n"); + } + return seq->data + (seq->size-1); +} + +static inline void SeqPop(Seq * seq) { + if (seq->size >= seq->allocated) { + printf("seq size is too large.\n"); + } + if (seq->size == 0) { + printf("seq size is too small.\n"); + } + seq->size -= 1; +} + +static inline Seq * SeqCreate(uint64_t len) { + Seq * seq = (Seq*)malloc(sizeof(Seq)); // NOLINT(*) + memset(seq, 0, sizeof(Seq)); + seq->allocated = len; + seq->data = (uint32_t*)malloc(sizeof(uint32_t)*len); // NOLINT(*) + seq->push_back = SeqPush; + seq->back = SeqBack; + seq->pop_back = SeqPop; + return seq; +} + +static inline void SeqRelease(Seq ** seq) { + free((*seq)->data); + free(*seq); +} + + +// implementations of JSONReader + +/*! + * \brief Takes the next char from the input source. + * \return the next character. + */ +static inline char JSONReader_NextChar(JSONReader * reader) { + char ch = reader->isptr[0]; + reader->isptr += 1; + return ch; +} + +/*! + * \brief Returns the next char from the input source. + * \return the next character. + */ +static inline char JSONReader_PeekNextChar(JSONReader * reader) { + return reader->isptr[0]; +} + +/*! + * \brief Read next nonspace character. + * \return the next nonspace character. + */ +static inline char JSONReader_NextNonSpace(JSONReader * reader) { + int ch; + do { + ch = reader->NextChar(reader); + if (ch == '\n') { ++(reader->line_count_n_); } + if (ch == '\r') { ++(reader->line_count_r_); } + } while (isspace(ch)); + return ch; +} + +/*! + * \brief Read just before next nonspace but not read that. + * \return the next nonspace character. + */ +static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { + int ch; + while (1) { + ch = reader->PeekNextChar(reader); + if (ch == '\n') { ++(reader->line_count_n_); } + if (ch == '\r') { ++(reader->line_count_r_); } + if (!isspace(ch)) break; + reader->NextChar(reader); + } + return ch; +} + +/*! + * \brief Parse next JSON string. + * \param out_str the output string. + * \throw dmlc::Error when next token is not string + */ +static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { + int status = 0; + char ch = reader->NextNonSpace(reader); + char output[128]; + uint32_t output_counter = 0; + memset(output, 0, 128); + while (1) { + ch = reader->NextChar(reader); + if (ch == '\\') { + char sch = reader->NextChar(reader); + switch (sch) { + case 'r': snprintf(output, sizeof(output), "%s\r", output); break; + case 'n': snprintf(output, sizeof(output), "%s\n", output); break; + case '\\': snprintf(output, sizeof(output), "%s\\", output); break; + case 't': snprintf(output, sizeof(output), "%s\t", output); break; + case '\"': snprintf(output, sizeof(output), "%s\"", output); break; + default: fprintf(stderr, "unknown string escape %c\n", sch); + } + } else { + if (ch == '\"') { break; } + if (strlen(output) >= 127) { + fprintf(stderr, "Error: detected buffer overflow.\n"); + status = -1; + break; + } + strncat(output, &ch, 1); + output_counter++; + if (output_counter >= 127) { + fprintf(stderr, "Error: string size greater than 128.\n"); + status = -1; + break; + } + } + if (ch == EOF || ch == '\r' || ch == '\n') { + fprintf(stderr, "Error at line X, Expect \'\"\' but reach end of line\n"); + } + } + snprintf(out_str, sizeof(output), "%s", output); + return status; +} + +static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { + int status = 0; + char* endptr; + const char* icstr = reader->isptr; + unsigned int number = strtol(icstr, &endptr, 10); + reader->isptr += endptr - icstr; + *out_value = number; + return status; +} + + +static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { + int status = 0; + char* endptr; + const char* icstr = reader->isptr; + int64_t number = strtol(icstr, &endptr, 10); + reader->isptr += endptr - icstr; + *out_value = number; + return status; +} + +/*! + * \brief Begin parsing an object. + * \code + * string key; + * // value can be any type that is json serializable. + * string value; + * reader->BeginObject(); + * while (reader->NextObjectItem(&key)) { + * // do somthing to key value + * reader->Read(&value); + * } + * \endcode + */ +static inline void JSONReader_BeginObject(JSONReader * reader) { + int ch = reader->NextNonSpace(reader); + if (!(ch == '{')) { + fprintf(stderr, "Error at line X, Expect \'{\' but got \'%c\'\n", ch); + } + Seq * scope_counter_ = reader->scope_counter_; + scope_counter_->push_back(scope_counter_, 0); +} + +/*! + * \brief Try to move to next object item. + * If this call is successful, user can proceed to call + * reader->Read to read in the value. + * \param out_key the key to the next object. + * \return true if the read is successful, false if we are at end of the object. + */ +static inline uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { + uint8_t next = 1; + Seq * scope_counter_ = reader->scope_counter_; + if (scope_counter_->back(scope_counter_)[0] != 0) { + int ch = reader->NextNonSpace(reader); + if (ch == EOF) { + next = 0; + } else if (ch == '}') { + next = 0; + } else { + if (ch != ',') { + fprintf(stderr, "Error at line X, JSON object expect \'}\' or \',\' but got \'%c\'\n", ch); + } + } + } else { + int ch = reader->PeekNextNonSpace(reader); + if (ch == '}') { + reader->NextChar(reader); + next = 0; + } + } + if (!next) { + scope_counter_->pop_back(scope_counter_); + return 0; + } else { + scope_counter_->back(scope_counter_)[0] += 1; + reader->ReadString(reader, out_key); + int ch = reader->NextNonSpace(reader); + if (ch != ':') { + fprintf(stderr, "Error at line X, Expect \':\' but get \'%c\'\n", ch); + } + return 1; + } +} + +/*! + * \brief Begin parsing an array. + * \code + * // value can be any type that is json serializable. + * string value; + * reader->BeginArray(); + * while (reader->NextArrayItem(&value)) { + * // do somthing to value + * } + * \endcode + */ +static inline void JSONReader_BeginArray(JSONReader * reader) { + int ch = reader->NextNonSpace(reader); + if (ch != '[') { + fprintf(stderr, "Error at line X, Expect \'[\' but get \'%c\'\n", ch); + } + Seq * scope_counter_ = reader->scope_counter_; + scope_counter_->push_back(scope_counter_, 0); +} + +/*! + * \brief Try to read the next element in the array. + * If this call is successful, user can proceed to call + * reader->Read to read in the value. + * \return true if the read is successful, false if we are at end of the array. + */ +static inline uint8_t JSONReader_NextArrayItem(JSONReader * reader) { + uint8_t next = 1; + Seq * scope_counter_ = reader->scope_counter_; + if (scope_counter_->back(scope_counter_)[0] != 0) { + int ch = reader->NextNonSpace(reader); + if (ch == EOF) { + next = 0; + } else if (ch == ']') { + next = 0; + } else { + if (ch != ',') { + fprintf(stderr, "Error at line X, JSON object expect \']\' or \',\' but got \'%c\'\n", ch); + } + } + } else { + int ch = reader->PeekNextNonSpace(reader); + if (ch == ']') { + reader->NextChar(reader); + next = 0; + } + } + if (!next) { + scope_counter_->pop_back(scope_counter_); + return 0; + } else { + scope_counter_->back(scope_counter_)[0] += 1; + return 1; + } +} + +/*! + * \brief Constructor. + * \param is the input source. + */ +JSONReader JSONReader_Create(const char * is) { + JSONReader reader; + memset(&reader, 0, sizeof(JSONReader)); + reader.scope_counter_ = SeqCreate(200); + reader.NextChar = JSONReader_NextChar; + reader.PeekNextChar = JSONReader_PeekNextChar; + reader.NextNonSpace = JSONReader_NextNonSpace; + reader.PeekNextNonSpace = JSONReader_PeekNextNonSpace; + reader.ReadString = JSONReader_ReadString; + reader.ReadUnsignedInteger = JSONReader_ReadUnsignedInteger; + reader.ReadInteger = JSONReader_ReadInteger; + reader.BeginArray = JSONReader_BeginArray; + reader.BeginObject = JSONReader_BeginObject; + reader.NextArrayItem = JSONReader_NextArrayItem; + reader.NextObjectItem = JSONReader_NextObjectItem; + reader.is_ = (char*)malloc(strlen(is)+1); // NOLINT(*) + memset(reader.is_, 0, strlen(is)+1); + snprintf(reader.is_, strlen(is)+1, "%s", is); + reader.isptr = reader.is_; + return reader; +} + +void JSONReader_Release(JSONReader * reader) { + SeqRelease(&(reader->scope_counter_)); + free(reader->is_); +} diff --git a/src/runtime/crt/load_json.h b/src/runtime/crt/load_json.h index 4dca9d9b1e1c..a1df0c76088b 100644 --- a/src/runtime/crt/load_json.h +++ b/src/runtime/crt/load_json.h @@ -41,61 +41,20 @@ enum { JSON_READ_TYPE_GRAPH_RUNTIME_GRAPH_ATTR = 11 }; -typedef struct seq_t { +typedef struct Seq { uint32_t * data; uint64_t allocated; uint32_t size; - void (*push_back)(struct seq_t * seq, uint32_t src); - uint32_t * (*back)(struct seq_t * seq); - void (*pop_back)(struct seq_t * seq); + void (*push_back)(struct Seq * seq, uint32_t src); + uint32_t * (*back)(struct Seq * seq); + void (*pop_back)(struct Seq * seq); } Seq; -static inline void SeqPush(Seq * seq, uint32_t src) { - if (seq->size >= seq->allocated) { - printf("seq too large.\n"); - } - seq->data[seq->size] = src; - seq->size += 1; -} - -static inline uint32_t * SeqBack(Seq * seq) { - if (seq->size >= seq->allocated) { - printf("seq too large.\n"); - } - return seq->data + (seq->size-1); -} - -static inline void SeqPop(Seq * seq) { - if (seq->size >= seq->allocated) { - printf("seq size is too large.\n"); - } - if (seq->size == 0) { - printf("seq size is too small.\n"); - } - seq->size -= 1; -} - -static inline Seq * SeqCreate(uint64_t len) { - Seq * seq = (Seq*)malloc(sizeof(Seq)); // NOLINT(*) - memset(seq, 0, sizeof(Seq)); - seq->allocated = len; - seq->data = (uint32_t*)malloc(sizeof(uint32_t)*len); // NOLINT(*) - seq->push_back = SeqPush; - seq->back = SeqBack; - seq->pop_back = SeqPop; - return seq; -} - -static inline void SeqRelease(Seq ** seq) { - free((*seq)->data); - free(*seq); -} - /*! * \brief Lightweight JSON Reader to read any STL compositions and structs. * The user need to know the schema of the */ -typedef struct json_reader_t { +typedef struct JSONReader { /*! \brief internal reader string */ /* char is_[TVM_CRT_MAX_JSON_LENGTH]; */ char * is_; @@ -110,343 +69,27 @@ typedef struct json_reader_t { */ Seq * scope_counter_; - char (*NextChar)(struct json_reader_t * reader); - char (*NextNonSpace)(struct json_reader_t * reader); - char (*PeekNextChar)(struct json_reader_t * reader); - char (*PeekNextNonSpace)(struct json_reader_t * reader); - int (*ReadUnsignedInteger)(struct json_reader_t * reader, unsigned int * out_value); - int (*ReadInteger)(struct json_reader_t * reader, int64_t * out_value); - int (*ReadString)(struct json_reader_t * reader, char * out_value); - void (*BeginArray)(struct json_reader_t * reader); - void (*BeginObject)(struct json_reader_t * reader); - uint8_t (*NextObjectItem)(struct json_reader_t * reader, char * out_key); - uint8_t (*NextArrayItem)(struct json_reader_t * reader); + char (*NextChar)(struct JSONReader * reader); + char (*NextNonSpace)(struct JSONReader * reader); + char (*PeekNextChar)(struct JSONReader * reader); + char (*PeekNextNonSpace)(struct JSONReader * reader); + int (*ReadUnsignedInteger)(struct JSONReader * reader, unsigned int * out_value); + int (*ReadInteger)(struct JSONReader * reader, int64_t * out_value); + int (*ReadString)(struct JSONReader * reader, char * out_value); + void (*BeginArray)(struct JSONReader * reader); + void (*BeginObject)(struct JSONReader * reader); + uint8_t (*NextObjectItem)(struct JSONReader * reader, char * out_key); + uint8_t (*NextArrayItem)(struct JSONReader * reader); } JSONReader; typedef void (*ReadFunction)(JSONReader *reader, void *addr); -/*! \brief internal data entry */ -struct JSONObjectReadHelperEntry { - /*! \brief the reader function */ - ReadFunction func; - /*! \brief the address to read */ - void *addr; - /*! \brief whether it is optional */ - uint8_t optional; -}; - -/*! - * \brief Helper class to read JSON into a class or struct object. - * \code - * struct Param { - * string name; - * int value; - * // define load function from JSON - * inline void Load(dmlc::JSONReader *reader) { - * dmlc::JSONStructReadHelper helper; - * helper.DeclareField("name", &name); - * helper.DeclareField("value", &value); - * helper.ReadAllFields(reader); - * } - * }; - * \endcode - */ -struct JSONObjectReadHelper { - /*! - * \brief Read in all the declared fields. - * \param reader the JSONReader to read the json. - */ - void (*ReadAllFields)(JSONReader *reader); - /*! - * \brief The internal reader function. - * \param reader The reader to read. - * \param addr The memory address to read. - */ - void (*ReaderFunction)(JSONReader *reader, void *addr); -}; - -#define DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName) \ - static DMLC_ATTRIBUTE_UNUSED ::dmlc::json::AnyJSONManager& \ - __make_AnyJSONType ## _ ## KeyName ## __ - -/*! - * \def DMLC_JSON_ENABLE_ANY - * \brief Macro to enable save/load JSON of dmlc:: whose actual type is Type. - * Any type will be saved as json array [KeyName, content] - * - * \param Type The type to be registered. - * \param KeyName The Type key assigned to the type, must be same during load. - */ -#define DMLC_JSON_ENABLE_ANY(Type, KeyName) \ - DMLC_STR_CONCAT(DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName), __COUNTER__) = \ - ::dmlc::json::AnyJSONManager::Global()->EnableType(#KeyName) \ - -// implementations of JSONReader - -/*! - * \brief Takes the next char from the input source. - * \return the next character. - */ -static inline char JSONReader_NextChar(JSONReader * reader) { - char ch = reader->isptr[0]; - reader->isptr += 1; - return ch; -} - -/*! - * \brief Returns the next char from the input source. - * \return the next character. - */ -static inline char JSONReader_PeekNextChar(JSONReader * reader) { - return reader->isptr[0]; -} - -/*! - * \brief Read next nonspace character. - * \return the next nonspace character. - */ -static inline char JSONReader_NextNonSpace(JSONReader * reader) { - int ch; - do { - ch = reader->NextChar(reader); - if (ch == '\n') { ++(reader->line_count_n_); } - if (ch == '\r') { ++(reader->line_count_r_); } - } while (isspace(ch)); - return ch; -} - -/*! - * \brief Read just before next nonspace but not read that. - * \return the next nonspace character. - */ -static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { - int ch; - while (1) { - ch = reader->PeekNextChar(reader); - if (ch == '\n') { ++(reader->line_count_n_); } - if (ch == '\r') { ++(reader->line_count_r_); } - if (!isspace(ch)) break; - reader->NextChar(reader); - } - return ch; -} - -/*! - * \brief Parse next JSON string. - * \param out_str the output string. - * \throw dmlc::Error when next token is not string - */ -static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { - int status = 0; - char ch = reader->NextNonSpace(reader); - char output[128]; - uint32_t output_counter = 0; - memset(output, 0, 128); - while (1) { - ch = reader->NextChar(reader); - if (ch == '\\') { - char sch = reader->NextChar(reader); - switch (sch) { - case 'r': snprintf(output, sizeof(output), "%s\r", output); break; - case 'n': snprintf(output, sizeof(output), "%s\n", output); break; - case '\\': snprintf(output, sizeof(output), "%s\\", output); break; - case 't': snprintf(output, sizeof(output), "%s\t", output); break; - case '\"': snprintf(output, sizeof(output), "%s\"", output); break; - default: fprintf(stderr, "unknown string escape %c\n", sch); - } - } else { - if (ch == '\"') { break; } - if (strlen(output) >= 127) { - fprintf(stderr, "Error: detected buffer overflow.\n"); - status = -1; - break; - } - strncat(output, &ch, 1); - output_counter++; - if (output_counter >= 127) { - fprintf(stderr, "Error: string size greater than 128.\n"); - status = -1; - break; - } - } - if (ch == EOF || ch == '\r' || ch == '\n') { - fprintf(stderr, "Error at line X, Expect \'\"\' but reach end of line\n"); - } - } - snprintf(out_str, sizeof(output), "%s", output); - return status; -} - -static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { - int status = 0; - char* endptr; - const char* icstr = reader->isptr; - unsigned int number = strtol(icstr, &endptr, 10); - reader->isptr += endptr - icstr; - *out_value = number; - return status; -} - - -static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { - int status = 0; - char* endptr; - const char* icstr = reader->isptr; - int64_t number = strtol(icstr, &endptr, 10); - reader->isptr += endptr - icstr; - *out_value = number; - return status; -} - -/*! - * \brief Begin parsing an object. - * \code - * string key; - * // value can be any type that is json serializable. - * string value; - * reader->BeginObject(); - * while (reader->NextObjectItem(&key)) { - * // do somthing to key value - * reader->Read(&value); - * } - * \endcode - */ -static inline void JSONReader_BeginObject(JSONReader * reader) { - int ch = reader->NextNonSpace(reader); - if (!(ch == '{')) { - fprintf(stderr, "Error at line X, Expect \'{\' but got \'%c\'\n", ch); - } - Seq * scope_counter_ = reader->scope_counter_; - scope_counter_->push_back(scope_counter_, 0); -} - -/*! - * \brief Try to move to next object item. - * If this call is successful, user can proceed to call - * reader->Read to read in the value. - * \param out_key the key to the next object. - * \return true if the read is successful, false if we are at end of the object. - */ -static inline uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { - uint8_t next = 1; - Seq * scope_counter_ = reader->scope_counter_; - if (scope_counter_->back(scope_counter_)[0] != 0) { - int ch = reader->NextNonSpace(reader); - if (ch == EOF) { - next = 0; - } else if (ch == '}') { - next = 0; - } else { - if (ch != ',') { - fprintf(stderr, "Error at line X, JSON object expect \'}\' or \',\' but got \'%c\'\n", ch); - } - } - } else { - int ch = reader->PeekNextNonSpace(reader); - if (ch == '}') { - reader->NextChar(reader); - next = 0; - } - } - if (!next) { - scope_counter_->pop_back(scope_counter_); - return 0; - } else { - scope_counter_->back(scope_counter_)[0] += 1; - reader->ReadString(reader, out_key); - int ch = reader->NextNonSpace(reader); - if (ch != ':') { - fprintf(stderr, "Error at line X, Expect \':\' but get \'%c\'\n", ch); - } - return 1; - } -} - -/*! - * \brief Begin parsing an array. - * \code - * // value can be any type that is json serializable. - * string value; - * reader->BeginArray(); - * while (reader->NextArrayItem(&value)) { - * // do somthing to value - * } - * \endcode - */ -static inline void JSONReader_BeginArray(JSONReader * reader) { - int ch = reader->NextNonSpace(reader); - if (ch != '[') { - fprintf(stderr, "Error at line X, Expect \'[\' but get \'%c\'\n", ch); - } - Seq * scope_counter_ = reader->scope_counter_; - scope_counter_->push_back(scope_counter_, 0); -} - -/*! - * \brief Try to read the next element in the array. - * If this call is successful, user can proceed to call - * reader->Read to read in the value. - * \return true if the read is successful, false if we are at end of the array. - */ -static inline uint8_t JSONReader_NextArrayItem(JSONReader * reader) { - uint8_t next = 1; - Seq * scope_counter_ = reader->scope_counter_; - if (scope_counter_->back(scope_counter_)[0] != 0) { - int ch = reader->NextNonSpace(reader); - if (ch == EOF) { - next = 0; - } else if (ch == ']') { - next = 0; - } else { - if (ch != ',') { - fprintf(stderr, "Error at line X, JSON object expect \']\' or \',\' but got \'%c\'\n", ch); - } - } - } else { - int ch = reader->PeekNextNonSpace(reader); - if (ch == ']') { - reader->NextChar(reader); - next = 0; - } - } - if (!next) { - scope_counter_->pop_back(scope_counter_); - return 0; - } else { - scope_counter_->back(scope_counter_)[0] += 1; - return 1; - } -} - /*! * \brief Constructor. * \param is the input source. */ -static inline JSONReader JSONReader_Create(const char * is) { - JSONReader reader; - memset(&reader, 0, sizeof(JSONReader)); - reader.scope_counter_ = SeqCreate(200); - reader.NextChar = JSONReader_NextChar; - reader.PeekNextChar = JSONReader_PeekNextChar; - reader.NextNonSpace = JSONReader_NextNonSpace; - reader.PeekNextNonSpace = JSONReader_PeekNextNonSpace; - reader.ReadString = JSONReader_ReadString; - reader.ReadUnsignedInteger = JSONReader_ReadUnsignedInteger; - reader.ReadInteger = JSONReader_ReadInteger; - reader.BeginArray = JSONReader_BeginArray; - reader.BeginObject = JSONReader_BeginObject; - reader.NextArrayItem = JSONReader_NextArrayItem; - reader.NextObjectItem = JSONReader_NextObjectItem; - reader.is_ = (char*)malloc(strlen(is)+1); // NOLINT(*) - memset(reader.is_, 0, strlen(is)+1); - snprintf(reader.is_, strlen(is)+1, "%s", is); - reader.isptr = reader.is_; - return reader; -} +JSONReader JSONReader_Create(const char * is); -static inline void JSONReader_Release(JSONReader * reader) { - SeqRelease(&(reader->scope_counter_)); - free(reader->is_); -} +void JSONReader_Release(JSONReader * reader); #endif // TVM_RUNTIME_CRT_LOAD_JSON_H_ diff --git a/src/runtime/crt/module.h b/src/runtime/crt/module.h index 517e2c4a1d1e..66b70b5694f2 100644 --- a/src/runtime/crt/module.h +++ b/src/runtime/crt/module.h @@ -27,13 +27,13 @@ #include #include -struct packed_func_t; -typedef struct packed_func_t PackedFunc; +struct TVMPackedFunc; +typedef struct TVMPackedFunc TVMPackedFunc; /*! * \brief Module container of TVM. */ -typedef struct module_t { +typedef struct TVMModule { /*! * \brief Get packed function from current module by name. * @@ -43,10 +43,10 @@ typedef struct module_t { * This function will return PackedFunc(nullptr) if function do not exist. * \note Implemented in packed_func.cc */ - void (*GetFunction)(const char * name, PackedFunc * pf); - void (*set_input)(const struct module_t * mod, const char * name, DLTensor * data); - void (*load_params)(const struct module_t * mod, const TVMByteArray * params_arr); - void (*run)(const struct module_t * mod); -} Module; + void (*GetFunction)(const char * name, TVMPackedFunc * pf); + void (*set_input)(const struct TVMModule * mod, const char * name, DLTensor * data); + void (*load_params)(const struct TVMModule * mod, const TVMByteArray * params_arr); + void (*run)(const struct TVMModule * mod); +} TVMModule; #endif // TVM_RUNTIME_CRT_MODULE_H_ diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index b981719bdff6..e2178d775caf 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -24,8 +24,86 @@ #include "ndarray.h" -NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, uint32_t ndim, DLDataType dtype) { - NDArray ret = NDArray_Create(ndim, shape, dtype, arr->dl_tensor.ctx); +TVMNDArray TVMNDArray_Create(uint32_t ndim, int64_t * shape, + DLDataType dtype, DLContext ctx) { + TVMNDArray ret; + memset(&ret, 0, sizeof(TVMNDArray)); + ret.dl_tensor.ndim = ndim; + ret.dl_tensor.shape = (int64_t*)malloc(sizeof(int64_t)*ndim); // NOLINT(*) + memcpy(ret.dl_tensor.shape, shape, sizeof(int64_t)*ndim); + ret.dl_tensor.dtype = dtype; + ret.dl_tensor.ctx = ctx; + ret.dl_tensor.data = 0; + return ret; +} + +TVMNDArray TVMNDArray_Empty(uint32_t ndim, int64_t * shape, + DLDataType dtype, DLContext ctx) { + TVMNDArray ret = TVMNDArray_Create(ndim, shape, dtype, ctx); + int64_t num_elems = 1; + int elem_bytes = (dtype.bits + 7) / 8; + uint32_t idx; + for (idx = 0; idx < ret.dl_tensor.ndim; ++idx) { + num_elems *= shape[idx]; + } + ret.dl_tensor.data = TVMBackendAllocWorkspace(kDLCPU, 0, num_elems, dtype.code, dtype.bits); + memset(ret.dl_tensor.data, 0, num_elems * elem_bytes); + return ret; +} + +int TVMNDArray_Load(TVMNDArray * ret, const char ** strm) { + int32_t status = 0; + uint64_t header, reserved; + header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); // NOLINT(*) + if (header != kTVMNDArrayMagic) { + fprintf(stderr, "Invalid DLTensor file format\n"); + status = -1; + } + reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); // NOLINT(*) + DLContext ctx; + uint32_t ndim; + DLDataType dtype; + ctx = ((DLContext*)*strm)[0]; *strm += sizeof(ctx); // NOLINT(*) + ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); // NOLINT(*) + dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); // NOLINT(*) + if ((ndim <= 0) || (ndim > TVM_CRT_MAX_NDIM)) { + fprintf(stderr, "Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); + status = -1; + } + if (ctx.device_type != kDLCPU) { + fprintf(stderr, "Invalid DLTensor context: can only save as CPU tensor\n"); + status = -1; + } + int64_t shape[TVM_CRT_MAX_NDIM]; + uint32_t idx; + if (ndim != 0) { + for (idx = 0; idx < ndim; idx++) { + shape[idx] = ((int64_t*)*strm)[0]; *strm += sizeof(shape[idx]); // NOLINT(*) + } + } + *ret = TVMNDArray_Empty(ndim, shape, dtype, ctx); + int64_t num_elems = 1; + int elem_bytes = (ret->dl_tensor.dtype.bits + 7) / 8; + for (idx = 0; idx < ret->dl_tensor.ndim; ++idx) { + num_elems *= ret->dl_tensor.shape[idx]; + } + int64_t data_byte_size; + data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); // NOLINT(*) + if (!(data_byte_size == num_elems * elem_bytes)) { + fprintf(stderr, "invalid DLTensor file format: data_byte_size=%ld, " + "while num_elems*elem_bytes=%ld\n", + data_byte_size, (num_elems * elem_bytes)); + status = -1; + } + memcpy(ret->dl_tensor.data, *strm, data_byte_size); + *strm += data_byte_size; + + return status; +} + +TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, int64_t * shape, + uint32_t ndim, DLDataType dtype) { + TVMNDArray ret = TVMNDArray_Create(ndim, shape, dtype, arr->dl_tensor.ctx); ret.dl_tensor.data = arr->dl_tensor.data; return ret; } diff --git a/src/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h index 98646f317372..639232ae8f94 100644 --- a/src/runtime/crt/ndarray.h +++ b/src/runtime/crt/ndarray.h @@ -35,87 +35,20 @@ /*! \brief Magic number for NDArray file */ static const uint64_t kTVMNDArrayMagic = 0xDD5E40F096B4A13F; -typedef struct ndarray_t { - DLTensor dl_tensor; -} NDArray; +/*! \brief Magic number for NDArray list file */ +static const uint64_t kTVMNDArrayListMagic = 0xF7E58D4F05049CB7; -NDArray NDArray_CreateView(NDArray * arr, int64_t * shape, uint32_t ndim, DLDataType dtype); +typedef struct TVMNDArray { + DLTensor dl_tensor; +} TVMNDArray; -static inline NDArray NDArray_Create(uint32_t ndim, int64_t * shape, - DLDataType dtype, DLContext ctx) { - NDArray ret; - memset(&ret, 0, sizeof(NDArray)); - ret.dl_tensor.ndim = ndim; - ret.dl_tensor.shape = (int64_t*)malloc(sizeof(int64_t)*ndim); // NOLINT(*) - memcpy(ret.dl_tensor.shape, shape, sizeof(int64_t)*ndim); - ret.dl_tensor.dtype = dtype; - ret.dl_tensor.ctx = ctx; - ret.dl_tensor.data = 0; - return ret; -} +TVMNDArray TVMNDArray_Create(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx); -static inline NDArray NDArray_Empty(uint32_t ndim, int64_t * shape, - DLDataType dtype, DLContext ctx) { - NDArray ret = NDArray_Create(ndim, shape, dtype, ctx); - int64_t num_elems = 1; - int elem_bytes = (dtype.bits + 7) / 8; - uint32_t idx; - for (idx = 0; idx < ret.dl_tensor.ndim; ++idx) { - num_elems *= shape[idx]; - } - ret.dl_tensor.data = TVMBackendAllocWorkspace(kDLCPU, 0, num_elems, dtype.code, dtype.bits); - memset(ret.dl_tensor.data, 0, num_elems * elem_bytes); - return ret; -} +TVMNDArray TVMNDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx); -static inline int NDArray_Load(NDArray * ret, const char ** strm) { - int32_t status = 0; - uint64_t header, reserved; - header = ((uint64_t*)*strm)[0]; *strm += sizeof(header); // NOLINT(*) - if (header != kTVMNDArrayMagic) { - fprintf(stderr, "Invalid DLTensor file format\n"); - status = -1; - } - reserved = ((uint64_t*)*strm)[0]; *strm += sizeof(reserved); // NOLINT(*) - DLContext ctx; - uint32_t ndim; - DLDataType dtype; - ctx = ((DLContext*)*strm)[0]; *strm += sizeof(ctx); // NOLINT(*) - ndim = ((uint32_t*)*strm)[0]; *strm += sizeof(ndim); // NOLINT(*) - dtype = ((DLDataType*)*strm)[0]; *strm += sizeof(dtype); // NOLINT(*) - if ((ndim <= 0) || (ndim > TVM_CRT_MAX_NDIM)) { - fprintf(stderr, "Invalid ndim=%d: expected to be 1 ~ %d.\n", ndim, TVM_CRT_MAX_NDIM); - status = -1; - } - if (ctx.device_type != kDLCPU) { - fprintf(stderr, "Invalid DLTensor context: can only save as CPU tensor\n"); - status = -1; - } - int64_t shape[TVM_CRT_MAX_NDIM]; - uint32_t idx; - if (ndim != 0) { - for (idx = 0; idx < ndim; idx++) { - shape[idx] = ((int64_t*)*strm)[0]; *strm += sizeof(shape[idx]); // NOLINT(*) - } - } - *ret = NDArray_Empty(ndim, shape, dtype, ctx); - int64_t num_elems = 1; - int elem_bytes = (ret->dl_tensor.dtype.bits + 7) / 8; - for (idx = 0; idx < ret->dl_tensor.ndim; ++idx) { - num_elems *= ret->dl_tensor.shape[idx]; - } - int64_t data_byte_size; - data_byte_size = ((int64_t*)*strm)[0]; *strm += sizeof(data_byte_size); // NOLINT(*) - if (!(data_byte_size == num_elems * elem_bytes)) { - fprintf(stderr, "invalid DLTensor file format: data_byte_size=%ld, " - "while num_elems*elem_bytes=%ld\n", - data_byte_size, (num_elems * elem_bytes)); - status = -1; - } - memcpy(ret->dl_tensor.data, *strm, data_byte_size); - *strm += data_byte_size; +int TVMNDArray_Load(TVMNDArray * ret, const char ** strm); - return status; -} +TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, int64_t * shape, + uint32_t ndim, DLDataType dtype); #endif // TVM_RUNTIME_CRT_NDARRAY_H_ diff --git a/src/runtime/crt/packed_func.h b/src/runtime/crt/packed_func.h index fd6383a8be4d..6fc1d8c417ca 100644 --- a/src/runtime/crt/packed_func.h +++ b/src/runtime/crt/packed_func.h @@ -28,14 +28,10 @@ #include #include +#include #include "module.h" -// Whether use TVM runtime in header only mode. -#ifndef TVM_RUNTIME_HEADER_ONLY -#define TVM_RUNTIME_HEADER_ONLY 0 -#endif - static inline DLDataType String2DLDataType(const char * s) { DLDataType t; // handle None type @@ -77,7 +73,7 @@ static inline DLDataType String2DLDataType(const char * s) { return t; } -typedef struct tvm_args_t { +typedef struct TVMArgs { TVMValue values[TVM_CRT_MAX_ARGS]; uint32_t tcodes[TVM_CRT_MAX_ARGS]; uint32_t values_count; @@ -100,34 +96,35 @@ static inline int TVMNoOperation(TVMValue * args, int * type_codes, int num_args return 0; } -typedef struct packed_func_t { +typedef struct TVMPackedFunc { char name[200]; TVMPackedCFunc fexec; TVMArgs args; - void (*Call)(struct packed_func_t * pf); - void (*SetArgs)(struct packed_func_t * pf, const struct tvm_args_t * args); -} PackedFunc; + void (*Call)(struct TVMPackedFunc * pf); + void (*SetArgs)(struct TVMPackedFunc * pf, const struct TVMArgs * args); +} TVMPackedFunc; -static inline void PackedFunc_Call(PackedFunc * pf) { +static inline void TVMPackedFunc_Call(TVMPackedFunc * pf) { pf->fexec(pf->args.values, pf->args.tcodes, pf->args.values_count, 0, 0); } -static inline void PackedFunc_SetArgs(PackedFunc * pf, const TVMArgs * args) { +static inline void TVMPackedFunc_SetArgs(TVMPackedFunc * pf, const TVMArgs * args) { memcpy(&(pf->args), args, sizeof(TVMArgs)); } -PackedFunc fexecs[GRAPH_RUNTIME_MAX_NODES]; +TVMPackedFunc fexecs[GRAPH_RUNTIME_MAX_NODES]; -void PackedFunc_SetupExecs(); +void TVMPackedFunc_SetupExecs(); -// Implement Module::GetFunction -// Put implementation in this file so we have seen the PackedFunc -static inline void Module_GetFunction(const char * name, PackedFunc * pf) { +// Implement TVMModule::GetFunction +// Put implementation in this file so we have seen the TVMPackedFunc +static inline void TVMModule_GetFunction(const char * name, TVMPackedFunc * pf) { int idx; - memset(pf, 0, sizeof(PackedFunc)); + memset(pf, 0, sizeof(TVMPackedFunc)); + assert(strlen(name) <= sizeof(pf->name)); snprintf(pf->name, strlen(name), "%s", name); - pf->Call = PackedFunc_Call; - pf->SetArgs = PackedFunc_SetArgs; + pf->Call = TVMPackedFunc_Call; + pf->SetArgs = TVMPackedFunc_SetArgs; pf->fexec = &TVMNoOperation; for (idx = 0; idx < GRAPH_RUNTIME_MAX_NODES; idx++) { if (!strcmp(fexecs[idx].name, name)) { From cd4b9a3e795ad9e82403ab9d6c1bd109eba3853c Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 26 Feb 2020 15:27:21 +0800 Subject: [PATCH 17/31] refactoring --- src/runtime/crt/graph_runtime.c | 44 ++++++++++++++++----------------- src/runtime/crt/graph_runtime.h | 16 ++++++------ src/runtime/crt/load_json.c | 37 ++++++++++++++------------- src/runtime/crt/load_json.h | 5 +--- src/runtime/crt/module.h | 8 ++---- 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 551214e0eea3..14363a1712b7 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -27,7 +27,7 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif // MAX -static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { +uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { int64_t accum = 1; uint32_t idx; for (idx = 0; idx < ndim; idx++) { @@ -37,7 +37,7 @@ static inline uint32_t Shape_Accumulate(int64_t * shape, uint32_t ndim) { return accum; } -static inline int NodeEntry_Load(TVMGraphRuntimeNodeEntry * entry, JSONReader * reader) { +int NodeEntry_Load(TVMGraphRuntimeNodeEntry * entry, JSONReader * reader) { int status = 0; reader->BeginArray(reader); if (!(reader->NextArrayItem(reader))) { @@ -59,7 +59,7 @@ static inline int NodeEntry_Load(TVMGraphRuntimeNodeEntry * entry, JSONReader * return status; } -static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReader *reader, +void TVMGraphRuntimeNode_LoadAttrs(TVMGraphRuntimeNode * node, JSONReader *reader, TVMOpParam* param) { int bitmask = 0; char key[20], value[120]; @@ -88,7 +88,7 @@ static inline void GraphRuntimeNode_LoadAttrs(GraphRuntimeNode * node, JSONReade if (bitmask != (1|2|4|8)) { fprintf(stderr, "invalid format\n"); } } -static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *reader) { +int TVMGraphRuntimeNode_Load(TVMGraphRuntimeNode * node, JSONReader *reader) { int status = 0; reader->BeginObject(reader); int bitmask = 0; @@ -140,7 +140,7 @@ static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *rea } else if (!strcmp(key, "attr") || !strcmp(key, "attrs")) { TVMOpParam param; - GraphRuntimeNode_LoadAttrs(node, reader, ¶m); + TVMGraphRuntimeNode_LoadAttrs(node, reader, ¶m); memcpy(&node->param, ¶m, sizeof(param)); } else if (!strcmp(key, "control_deps")) { fprintf(stderr, "do not support key %s", key); @@ -155,15 +155,15 @@ static inline int GraphRuntimeNode_Load(GraphRuntimeNode * node, JSONReader *rea return status; } -static inline GraphRuntimeNode GraphRuntimeNodeCreate() { - GraphRuntimeNode node; - memset(&node, 0, sizeof(GraphRuntimeNode)); - node.LoadAttrs = GraphRuntimeNode_LoadAttrs; - node.Load = GraphRuntimeNode_Load; +TVMGraphRuntimeNode TVMGraphRuntimeNodeCreate() { + TVMGraphRuntimeNode node; + memset(&node, 0, sizeof(TVMGraphRuntimeNode)); + node.LoadAttrs = TVMGraphRuntimeNode_LoadAttrs; + node.Load = TVMGraphRuntimeNode_Load; return node; } -static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONReader *reader) { +int TVMGraphRuntimeGraphAttr_Load(TVMGraphRuntimeGraphAttr * attr, JSONReader *reader) { int status = 0; int bitmask = 0; char key[16], type[16]; @@ -273,7 +273,7 @@ static inline int GraphRuntimeGraphAttr_Load(GraphRuntimeGraphAttr * attr, JSONR return status; } -static inline int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *reader) { +int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *reader) { int status = 0; reader->BeginObject(reader); int bitmask = 0; @@ -282,8 +282,8 @@ static inline int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *re if (!strcmp(key, "nodes")) { reader->BeginArray(reader); while (reader->NextArrayItem(reader)) { - GraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; - status = GraphRuntimeNode_Load(node, reader); + TVMGraphRuntimeNode * node = runtime->nodes + runtime->nodes_count; + status = TVMGraphRuntimeNode_Load(node, reader); if (status != 0) { fprintf(stderr, "failed to load an element in `nodes` field in graph runtime node.\n"); break; @@ -325,7 +325,7 @@ static inline int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *re } bitmask |= 8; } else if (!strcmp(key, "attrs")) { - status = GraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); + status = TVMGraphRuntimeGraphAttr_Load(&(runtime->attrs), reader); if (status != 0) { fprintf(stderr, "Fail to load an element in `heads` field in graph runtime node.\n"); break; @@ -343,7 +343,7 @@ static inline int TVMGraphRuntime_Load(TVMGraphRuntime * runtime, JSONReader *re return status; } -static inline uint32_t TVMGraphRuntime_GetEntryId(TVMGraphRuntime * runtime, +uint32_t TVMGraphRuntime_GetEntryId(TVMGraphRuntime * runtime, uint32_t nid, uint32_t index) { return runtime->node_row_ptr[nid] + index; } @@ -487,7 +487,7 @@ void TVMGraphRuntime_SetupStorage(TVMGraphRuntime * runtime) { // Grab saved optimization plan from graph. DLDataType vtype[GRAPH_RUNTIME_MAX_NODES]; - GraphRuntimeGraphAttr * attrs = &(runtime->attrs); + TVMGraphRuntimeGraphAttr * attrs = &(runtime->attrs); for (idx = 0; idx < attrs->dltype_count; idx++) { vtype[idx] = String2DLDataType(attrs->dltype[idx]); } @@ -549,7 +549,7 @@ int TVMGraphRuntime_SetupOpExecs(TVMGraphRuntime * runtime) { uint32_t nid, idx; runtime->op_execs_count = runtime->nodes_count; for (nid = 0; nid < runtime->nodes_count; nid++) { - const GraphRuntimeNode * inode = runtime->nodes + nid; + const TVMGraphRuntimeNode * inode = runtime->nodes + nid; if (strcmp(inode->op_type, "null")) { DLTensorPtr args[GRAPH_RUNTIME_MAX_NODES]; uint32_t args_count = 0; @@ -585,7 +585,7 @@ int TVMGraphRuntime_SetupOpExecs(TVMGraphRuntime * runtime) { return status; } -typedef struct OpArgs { +typedef struct TVMOpArgs { DLTensor args[TVM_CRT_MAX_ARGS]; uint32_t args_count; TVMValue arg_values[TVM_CRT_MAX_ARGS]; @@ -594,14 +594,14 @@ typedef struct OpArgs { uint32_t arg_tcodes_count; int64_t shape_data[TVM_CRT_MAX_ARGS]; uint32_t shape_data_count; -} OpArgs; +} TVMOpArgs; int32_t TVMGraphRuntime_CreateTVMOp(TVMGraphRuntime * runtime, const TVMOpParam * param, DLTensorPtr * args, const uint32_t args_count, uint32_t num_inputs, TVMPackedFunc * pf) { uint32_t idx; - OpArgs arg_ptr; - memset(&arg_ptr, 0, sizeof(OpArgs)); + TVMOpArgs arg_ptr; + memset(&arg_ptr, 0, sizeof(TVMOpArgs)); arg_ptr.args_count = args_count; if (param->flatten_data) { arg_ptr.shape_data_count = arg_ptr.args_count; diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index ee03ce56a3dd..fda08387211a 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -55,7 +55,7 @@ typedef struct TVMGraphRuntimeNodeEntry { } TVMGraphRuntimeNodeEntry; // Node -typedef struct graph_runtime_node_t { +typedef struct TVMGraphRuntimeNode { // operator type in string char op_type[16]; // name of the op @@ -68,13 +68,13 @@ typedef struct graph_runtime_node_t { // control deps uint32_t control_deps[200]; // JSON Loader - void (*LoadAttrs)(struct graph_runtime_node_t * node, JSONReader *reader, TVMOpParam* param); + void (*LoadAttrs)(struct TVMGraphRuntimeNode * node, JSONReader *reader, TVMOpParam* param); // JSON Loader - int (*Load)(struct graph_runtime_node_t * node, JSONReader *reader); -} GraphRuntimeNode; + int (*Load)(struct TVMGraphRuntimeNode * node, JSONReader *reader); +} TVMGraphRuntimeNode; // Graph attribute -typedef struct graph_runtime_graph_attr_t { +typedef struct TVMGraphRuntimeGraphAttr { uint32_t storage_num_not_alloctaed; uint32_t storage_id[GRAPH_RUNTIME_MAX_NODES]; uint32_t device_index[GRAPH_RUNTIME_MAX_NODES]; @@ -83,7 +83,7 @@ typedef struct graph_runtime_graph_attr_t { int64_t shape[GRAPH_RUNTIME_MAX_NODES][TVM_CRT_MAX_NDIM]; uint32_t ndim[GRAPH_RUNTIME_MAX_NODES]; uint32_t shape_count; -} GraphRuntimeGraphAttr; +} TVMGraphRuntimeGraphAttr; typedef DLTensor* DLTensorPtr; @@ -160,7 +160,7 @@ typedef struct TVMGraphRuntime { // /*! \brief The graph nodes. */ /* GraphRuntimeNode nodes_[GRAPH_RUNTIME_MAX_NODES]; */ - GraphRuntimeNode nodes[GRAPH_RUNTIME_MAX_NODES]; + TVMGraphRuntimeNode nodes[GRAPH_RUNTIME_MAX_NODES]; uint32_t nodes_count; /*! \brief The argument nodes. */ uint32_t input_nodes[GRAPH_RUNTIME_MAX_INPUT_NODES]; @@ -172,7 +172,7 @@ typedef struct TVMGraphRuntime { TVMGraphRuntimeNodeEntry outputs[GRAPH_RUNTIME_MAX_OUTPUTS]; uint32_t outputs_count; /*! \brief Additional graph attributes. */ - GraphRuntimeGraphAttr attrs; + TVMGraphRuntimeGraphAttr attrs; /*! \brief The code module that contains both host and device code. */ TVMModule module; /*! \brief Execution context of all devices including the host. */ diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index 42ae4460821c..f1f60578abf0 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -24,11 +24,11 @@ #include "load_json.h" // the node entry structure in serialized format -typedef struct _JSONNodeEntry { +typedef struct JSONNodeEntry { uint32_t node_id; uint32_t index; uint32_t version; - void (*Load)(struct _JSONNodeEntry * entry, JSONReader *reader); + void (*Load)(struct JSONNodeEntry * entry, JSONReader *reader); } JSONNodeEntry; void JSONNodeEntryLoad(JSONNodeEntry * entry, JSONReader *reader) { @@ -48,8 +48,7 @@ void JSONNodeEntryLoad(JSONNodeEntry * entry, JSONReader *reader) { // implementation of Seq class - -static inline void SeqPush(Seq * seq, uint32_t src) { +void SeqPush(Seq * seq, uint32_t src) { if (seq->size >= seq->allocated) { printf("seq too large.\n"); } @@ -57,14 +56,14 @@ static inline void SeqPush(Seq * seq, uint32_t src) { seq->size += 1; } -static inline uint32_t * SeqBack(Seq * seq) { +uint32_t * SeqBack(Seq * seq) { if (seq->size >= seq->allocated) { printf("seq too large.\n"); } return seq->data + (seq->size-1); } -static inline void SeqPop(Seq * seq) { +void SeqPop(Seq * seq) { if (seq->size >= seq->allocated) { printf("seq size is too large.\n"); } @@ -74,7 +73,7 @@ static inline void SeqPop(Seq * seq) { seq->size -= 1; } -static inline Seq * SeqCreate(uint64_t len) { +Seq * SeqCreate(uint64_t len) { Seq * seq = (Seq*)malloc(sizeof(Seq)); // NOLINT(*) memset(seq, 0, sizeof(Seq)); seq->allocated = len; @@ -85,7 +84,7 @@ static inline Seq * SeqCreate(uint64_t len) { return seq; } -static inline void SeqRelease(Seq ** seq) { +void SeqRelease(Seq ** seq) { free((*seq)->data); free(*seq); } @@ -97,7 +96,7 @@ static inline void SeqRelease(Seq ** seq) { * \brief Takes the next char from the input source. * \return the next character. */ -static inline char JSONReader_NextChar(JSONReader * reader) { +char JSONReader_NextChar(JSONReader * reader) { char ch = reader->isptr[0]; reader->isptr += 1; return ch; @@ -107,7 +106,7 @@ static inline char JSONReader_NextChar(JSONReader * reader) { * \brief Returns the next char from the input source. * \return the next character. */ -static inline char JSONReader_PeekNextChar(JSONReader * reader) { +char JSONReader_PeekNextChar(JSONReader * reader) { return reader->isptr[0]; } @@ -115,7 +114,7 @@ static inline char JSONReader_PeekNextChar(JSONReader * reader) { * \brief Read next nonspace character. * \return the next nonspace character. */ -static inline char JSONReader_NextNonSpace(JSONReader * reader) { +char JSONReader_NextNonSpace(JSONReader * reader) { int ch; do { ch = reader->NextChar(reader); @@ -129,7 +128,7 @@ static inline char JSONReader_NextNonSpace(JSONReader * reader) { * \brief Read just before next nonspace but not read that. * \return the next nonspace character. */ -static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { +char JSONReader_PeekNextNonSpace(JSONReader * reader) { int ch; while (1) { ch = reader->PeekNextChar(reader); @@ -146,7 +145,7 @@ static inline char JSONReader_PeekNextNonSpace(JSONReader * reader) { * \param out_str the output string. * \throw dmlc::Error when next token is not string */ -static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { +int JSONReader_ReadString(JSONReader * reader, char * out_str) { int status = 0; char ch = reader->NextNonSpace(reader); char output[128]; @@ -187,7 +186,7 @@ static inline int JSONReader_ReadString(JSONReader * reader, char * out_str) { return status; } -static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { +int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned int * out_value) { int status = 0; char* endptr; const char* icstr = reader->isptr; @@ -198,7 +197,7 @@ static inline int JSONReader_ReadUnsignedInteger(JSONReader * reader, unsigned i } -static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { +int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_value) { int status = 0; char* endptr; const char* icstr = reader->isptr; @@ -221,7 +220,7 @@ static inline int JSONReader_ReadInteger(JSONReader * reader, int64_t * out_valu * } * \endcode */ -static inline void JSONReader_BeginObject(JSONReader * reader) { +void JSONReader_BeginObject(JSONReader * reader) { int ch = reader->NextNonSpace(reader); if (!(ch == '{')) { fprintf(stderr, "Error at line X, Expect \'{\' but got \'%c\'\n", ch); @@ -237,7 +236,7 @@ static inline void JSONReader_BeginObject(JSONReader * reader) { * \param out_key the key to the next object. * \return true if the read is successful, false if we are at end of the object. */ -static inline uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { +uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_key) { uint8_t next = 1; Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { @@ -283,7 +282,7 @@ static inline uint8_t JSONReader_NextObjectItem(JSONReader * reader, char * out_ * } * \endcode */ -static inline void JSONReader_BeginArray(JSONReader * reader) { +void JSONReader_BeginArray(JSONReader * reader) { int ch = reader->NextNonSpace(reader); if (ch != '[') { fprintf(stderr, "Error at line X, Expect \'[\' but get \'%c\'\n", ch); @@ -298,7 +297,7 @@ static inline void JSONReader_BeginArray(JSONReader * reader) { * reader->Read to read in the value. * \return true if the read is successful, false if we are at end of the array. */ -static inline uint8_t JSONReader_NextArrayItem(JSONReader * reader) { +uint8_t JSONReader_NextArrayItem(JSONReader * reader) { uint8_t next = 1; Seq * scope_counter_ = reader->scope_counter_; if (scope_counter_->back(scope_counter_)[0] != 0) { diff --git a/src/runtime/crt/load_json.h b/src/runtime/crt/load_json.h index a1df0c76088b..a5df7a055af0 100644 --- a/src/runtime/crt/load_json.h +++ b/src/runtime/crt/load_json.h @@ -56,7 +56,6 @@ typedef struct Seq { */ typedef struct JSONReader { /*! \brief internal reader string */ - /* char is_[TVM_CRT_MAX_JSON_LENGTH]; */ char * is_; char * isptr; /*! \brief "\\r" counter */ @@ -82,10 +81,8 @@ typedef struct JSONReader { uint8_t (*NextArrayItem)(struct JSONReader * reader); } JSONReader; -typedef void (*ReadFunction)(JSONReader *reader, void *addr); - /*! - * \brief Constructor. + * \brief Constructor of JSONReader class * \param is the input source. */ JSONReader JSONReader_Create(const char * is); diff --git a/src/runtime/crt/module.h b/src/runtime/crt/module.h index 66b70b5694f2..8ff979b872e6 100644 --- a/src/runtime/crt/module.h +++ b/src/runtime/crt/module.h @@ -38,15 +38,11 @@ typedef struct TVMModule { * \brief Get packed function from current module by name. * * \param name The name of the function. - * \param query_imports Whether also query dependency modules. - * \return The result function. + * \param pf The result function. + * * This function will return PackedFunc(nullptr) if function do not exist. - * \note Implemented in packed_func.cc */ void (*GetFunction)(const char * name, TVMPackedFunc * pf); - void (*set_input)(const struct TVMModule * mod, const char * name, DLTensor * data); - void (*load_params)(const struct TVMModule * mod, const TVMByteArray * params_arr); - void (*run)(const struct TVMModule * mod); } TVMModule; #endif // TVM_RUNTIME_CRT_MODULE_H_ From 62d1098bce8e374d0ca6d85c424e89e6e3c85a08 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Wed, 26 Feb 2020 16:38:40 +0800 Subject: [PATCH 18/31] refactoring --- apps/bundle_deploy_c/Makefile | 2 +- apps/bundle_deploy_c/demo.cc | 10 +++++++++- src/runtime/crt/bundle.c | 18 +++++++++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 6af557442db2..ab22ae62f143 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -73,7 +73,7 @@ $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir # Build our bundle against the serialized bundle.c API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: runtime.c $(build_dir)/model.o $(build_dir)/graph.json.o $(build_dir)/params.bin.o $(build_dir)/bridge.c +$(build_dir)/bundle.so: runtime.c $(build_dir)/model.o $(build_dir)/bridge.c @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc index a7684ca9ed86..ce7f400d29d4 100644 --- a/apps/bundle_deploy_c/demo.cc +++ b/apps/bundle_deploy_c/demo.cc @@ -25,6 +25,9 @@ #include #include +#include "build/graph.json.c" +#include "build/params.bin.c" + template auto getFunc(void *bundle, const char *name) { dlerror(); auto *f = @@ -38,7 +41,12 @@ int main(int argc, char **argv) { auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); assert(bundle); - auto *handle = getFunc(bundle, "tvm_runtime_create")(); + char * json_data = reinterpret_cast(build_graph_json); + char * params_data = reinterpret_cast(build_params_bin); + uint64_t params_size = build_params_bin_len; + + auto *handle = getFunc(bundle, "tvm_runtime_create")( + json_data, params_data, params_size); float input_storage[1 * 3 * 224 * 224]; FILE * fp = fopen(argv[2], "rb"); diff --git a/src/runtime/crt/bundle.c b/src/runtime/crt/bundle.c index eb1b86bf69e3..7b2a8f6509bc 100644 --- a/src/runtime/crt/bundle.c +++ b/src/runtime/crt/bundle.c @@ -24,15 +24,15 @@ extern unsigned int build_graph_json_len; extern unsigned char build_params_bin[]; extern unsigned int build_params_bin_len; -TVM_DLL TVMGraphRuntime * tvm_runtime_create() { - char * json_data = build_graph_json; - - int device_type = kDLCPU; - int device_id = 0; +TVM_DLL TVMGraphRuntime * tvm_runtime_create(const char * json_data, + const char * params_data, + const uint64_t params_size) { + int64_t device_type = kDLCPU; + int64_t device_id = 0; TVMByteArray params; - params.data = build_params_bin; - params.size = build_params_bin_len; + params.data = params_data; + params.size = params_size; TVMContext ctx; ctx.device_type = device_type; @@ -49,7 +49,7 @@ TVM_DLL void tvm_runtime_destroy(TVMGraphRuntime * runtime) { } TVM_DLL void tvm_runtime_set_input(TVMGraphRuntime * runtime, const char * name, - DLTensor * tensor) { + DLTensor * tensor) { runtime->SetInput(runtime, "data", tensor); } @@ -58,7 +58,7 @@ TVM_DLL void tvm_runtime_run(TVMGraphRuntime * runtime) { } TVM_DLL void tvm_runtime_get_output(TVMGraphRuntime * runtime, int32_t index, - DLTensor * tensor) { + DLTensor * tensor) { runtime->GetOutput(runtime, index, tensor); } From 2b0411e24b059aa3fb22ac57edd104cd1d5bf961 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 27 Feb 2020 16:26:01 +0800 Subject: [PATCH 19/31] initial crt_runtime_api.c --- apps/bundle_deploy_c/Makefile | 4 +- apps/bundle_deploy_c/runtime.c | 11 ++-- src/runtime/crt/bundle.c | 5 -- .../{c_backend_api.c => crt_backend_api.c} | 10 +-- src/runtime/crt/crt_runtime_api.c | 66 +++++++++++++++++++ src/runtime/crt/graph_runtime.c | 3 +- src/runtime/crt/ndarray.c | 15 +++-- src/runtime/crt/ndarray.h | 8 ++- 8 files changed, 93 insertions(+), 29 deletions(-) rename src/runtime/crt/{c_backend_api.c => crt_backend_api.c} (87%) create mode 100644 src/runtime/crt/crt_runtime_api.c diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index ab22ae62f143..e3e6509df0a9 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -17,8 +17,10 @@ # Makefile Example to bundle TVM modules. -# Configure runtime +# Preserve debug feature for MISRA C DEBUG = 0 + +# Configure runtime MAX_NDIM = 6 MAX_ARGS = 10 GRAPH_RUNTIME_NODE_MAX_INPUTS = 300 diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index f52924f81083..d64927ed7575 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -17,11 +17,14 @@ * under the License. */ -#include -#include -#include +/* Explicitly declare posix_memalign function */ +#if _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif -#include "../../src/runtime/crt/c_backend_api.c" +#include "../../src/runtime/crt/crt_runtime_api.c" +#include "../../src/runtime/crt/crt_backend_api.c" #include "../../src/runtime/crt/graph_runtime.c" #include "../../src/runtime/crt/load_json.c" #include "../../src/runtime/crt/ndarray.c" diff --git a/src/runtime/crt/bundle.c b/src/runtime/crt/bundle.c index 7b2a8f6509bc..0b1d0a6fb981 100644 --- a/src/runtime/crt/bundle.c +++ b/src/runtime/crt/bundle.c @@ -19,11 +19,6 @@ #include "graph_runtime.h" -extern unsigned char build_graph_json[]; -extern unsigned int build_graph_json_len; -extern unsigned char build_params_bin[]; -extern unsigned int build_params_bin_len; - TVM_DLL TVMGraphRuntime * tvm_runtime_create(const char * json_data, const char * params_data, const uint64_t params_size) { diff --git a/src/runtime/crt/c_backend_api.c b/src/runtime/crt/crt_backend_api.c similarity index 87% rename from src/runtime/crt/c_backend_api.c rename to src/runtime/crt/crt_backend_api.c index f3e840122962..9c319ffcb29e 100644 --- a/src/runtime/crt/c_backend_api.c +++ b/src/runtime/crt/crt_backend_api.c @@ -17,7 +17,7 @@ * under the License. */ -#include +#include #include #include @@ -44,14 +44,6 @@ int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) { return 0; } -static char g_last_error[1024]; - -void TVMAPISetLastError(const char* msg) { - snprintf(g_last_error, sizeof(g_last_error), "%s", msg); -} - -const char* TVMGetLastError(void) { return g_last_error; } - int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_task) { TVMParallelGroupEnv env; env.num_task = 1; diff --git a/src/runtime/crt/crt_runtime_api.c b/src/runtime/crt/crt_runtime_api.c new file mode 100644 index 000000000000..c37b043ffbc1 --- /dev/null +++ b/src/runtime/crt/crt_runtime_api.c @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + +#include +#include +#include +#include + +#include "ndarray.h" + +// Handle internal errors + +static char g_last_error[1024]; + +void TVMAPISetLastError(const char* msg) { + assert(strlen(msg) < sizeof(g_last_error)); + snprintf(g_last_error, sizeof(g_last_error), "%s", msg); +} + +const char* TVMGetLastError(void) { return g_last_error; } + +// Manipulate NDArray on target device + +int TVMArrayAlloc(const tvm_index_t* shape, + int ndim, + int dtype_code, + int dtype_bits, + int dtype_lanes, + int device_type, + int device_id, + TVMArrayHandle* out) { + DLDataType dtype; + dtype.code = dtype_code; + dtype.bits = dtype_bits; + dtype.lanes = dtype_lanes; + DLContext ctx; + ctx.device_type = device_type; + ctx.device_id = device_id; + TVMNDArray arr = TVMNDArray_Create(ndim, shape, dtype, ctx); + **out = arr.dl_tensor; + return 0; +} + +int TVMArrayFree(TVMArrayHandle handle) { + TVMNDArray arr; + arr.dl_tensor = *handle; + return TVMNDArray_Release(&arr); +} diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 14363a1712b7..71a5bac46367 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -677,8 +677,7 @@ void TVMGraphRuntimeRelease(TVMGraphRuntime ** pptr) { int32_t idx; TVMGraphRuntime * runtime = *pptr; for (idx = 0; idx < runtime->storage_pool_count; ++idx) { - free(runtime->storage_pool[idx].dl_tensor.data); - free(runtime->storage_pool[idx].dl_tensor.shape); + TVMNDArray_Release(&(runtime->storage_pool[idx])); } free(*pptr); } diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index e2178d775caf..47136316c513 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -24,8 +24,8 @@ #include "ndarray.h" -TVMNDArray TVMNDArray_Create(uint32_t ndim, int64_t * shape, - DLDataType dtype, DLContext ctx) { +TVMNDArray TVMNDArray_Create(uint32_t ndim, const tvm_index_t * shape, + DLDataType dtype, DLContext ctx) { TVMNDArray ret; memset(&ret, 0, sizeof(TVMNDArray)); ret.dl_tensor.ndim = ndim; @@ -37,8 +37,8 @@ TVMNDArray TVMNDArray_Create(uint32_t ndim, int64_t * shape, return ret; } -TVMNDArray TVMNDArray_Empty(uint32_t ndim, int64_t * shape, - DLDataType dtype, DLContext ctx) { +TVMNDArray TVMNDArray_Empty(uint32_t ndim, const tvm_index_t * shape, + DLDataType dtype, DLContext ctx) { TVMNDArray ret = TVMNDArray_Create(ndim, shape, dtype, ctx); int64_t num_elems = 1; int elem_bytes = (dtype.bits + 7) / 8; @@ -101,9 +101,14 @@ int TVMNDArray_Load(TVMNDArray * ret, const char ** strm) { return status; } -TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, int64_t * shape, +TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, const tvm_index_t * shape, uint32_t ndim, DLDataType dtype) { TVMNDArray ret = TVMNDArray_Create(ndim, shape, dtype, arr->dl_tensor.ctx); ret.dl_tensor.data = arr->dl_tensor.data; return ret; } + +int TVMNDArray_Release(TVMNDArray * arr) { + free(arr->dl_tensor.data); + free(arr->dl_tensor.shape); +} diff --git a/src/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h index 639232ae8f94..009a1a174d95 100644 --- a/src/runtime/crt/ndarray.h +++ b/src/runtime/crt/ndarray.h @@ -42,13 +42,15 @@ typedef struct TVMNDArray { DLTensor dl_tensor; } TVMNDArray; -TVMNDArray TVMNDArray_Create(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx); +TVMNDArray TVMNDArray_Create(uint32_t ndim, const tvm_index_t * shape, DLDataType dtype, DLContext ctx); -TVMNDArray TVMNDArray_Empty(uint32_t ndim, int64_t * shape, DLDataType dtype, DLContext ctx); +TVMNDArray TVMNDArray_Empty(uint32_t ndim, const tvm_index_t * shape, DLDataType dtype, DLContext ctx); int TVMNDArray_Load(TVMNDArray * ret, const char ** strm); -TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, int64_t * shape, +TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, const tvm_index_t * shape, uint32_t ndim, DLDataType dtype); +int TVMNDArray_Release(TVMNDArray * arr); + #endif // TVM_RUNTIME_CRT_NDARRAY_H_ From 2bc880bcb3777c7c38beb97baf571ca8853eba92 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Fri, 28 Feb 2020 18:35:11 +0800 Subject: [PATCH 20/31] improved compatibility with g++ --- src/runtime/crt/bundle.c | 2 +- src/runtime/crt/crt_backend_api.c | 1 + src/runtime/crt/crt_runtime_api.c | 4 ++-- src/runtime/crt/ndarray.c | 1 + src/runtime/crt/packed_func.h | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/runtime/crt/bundle.c b/src/runtime/crt/bundle.c index 0b1d0a6fb981..ac6be10e15bf 100644 --- a/src/runtime/crt/bundle.c +++ b/src/runtime/crt/bundle.c @@ -30,7 +30,7 @@ TVM_DLL TVMGraphRuntime * tvm_runtime_create(const char * json_data, params.size = params_size; TVMContext ctx; - ctx.device_type = device_type; + ctx.device_type = (DLDeviceType)device_type; ctx.device_id = device_id; TVMGraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); diff --git a/src/runtime/crt/crt_backend_api.c b/src/runtime/crt/crt_backend_api.c index 9c319ffcb29e..7eff78d5e5aa 100644 --- a/src/runtime/crt/crt_backend_api.c +++ b/src/runtime/crt/crt_backend_api.c @@ -52,4 +52,5 @@ int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_ta } int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { + return 0; } diff --git a/src/runtime/crt/crt_runtime_api.c b/src/runtime/crt/crt_runtime_api.c index c37b043ffbc1..c153c0767e21 100644 --- a/src/runtime/crt/crt_runtime_api.c +++ b/src/runtime/crt/crt_runtime_api.c @@ -52,9 +52,9 @@ int TVMArrayAlloc(const tvm_index_t* shape, dtype.bits = dtype_bits; dtype.lanes = dtype_lanes; DLContext ctx; - ctx.device_type = device_type; + ctx.device_type = (DLDeviceType)device_type; ctx.device_id = device_id; - TVMNDArray arr = TVMNDArray_Create(ndim, shape, dtype, ctx); + TVMNDArray arr = TVMNDArray_Empty(ndim, shape, dtype, ctx); **out = arr.dl_tensor; return 0; } diff --git a/src/runtime/crt/ndarray.c b/src/runtime/crt/ndarray.c index 47136316c513..016fdd5add95 100644 --- a/src/runtime/crt/ndarray.c +++ b/src/runtime/crt/ndarray.c @@ -111,4 +111,5 @@ TVMNDArray TVMNDArray_CreateView(TVMNDArray * arr, const tvm_index_t * shape, int TVMNDArray_Release(TVMNDArray * arr) { free(arr->dl_tensor.data); free(arr->dl_tensor.shape); + return 0; } diff --git a/src/runtime/crt/packed_func.h b/src/runtime/crt/packed_func.h index 6fc1d8c417ca..6cec942f550c 100644 --- a/src/runtime/crt/packed_func.h +++ b/src/runtime/crt/packed_func.h @@ -75,7 +75,7 @@ static inline DLDataType String2DLDataType(const char * s) { typedef struct TVMArgs { TVMValue values[TVM_CRT_MAX_ARGS]; - uint32_t tcodes[TVM_CRT_MAX_ARGS]; + int tcodes[TVM_CRT_MAX_ARGS]; /* Data type should be identical to type_codes in TVMPackedCFunc */ uint32_t values_count; } TVMArgs; From 09571b7f84dcc58db40c55db4fab664305cdf8c2 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Fri, 28 Feb 2020 18:37:53 +0800 Subject: [PATCH 21/31] using exposed API in c_runtime_api.h --- apps/bundle_deploy_c/demo.c | 107 ++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 apps/bundle_deploy_c/demo.c diff --git a/apps/bundle_deploy_c/demo.c b/apps/bundle_deploy_c/demo.c new file mode 100644 index 000000000000..06eb34163104 --- /dev/null +++ b/apps/bundle_deploy_c/demo.c @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/*! + * \brief Example code on load and run TVM modules + * \file c_deploy.c + */ +#include + +#include +#include + +void Verify(TVMModuleHandle mod, const char * fname) { + // Get the function from the module. + TVMFunctionHandle f; + TVMModGetFunction(mod, fname, 0, &f); + + /* CHECK(f != nullptr); */ + + // Allocate the DLPack data structures. + // + // Note that we use TVM runtime API to allocate the DLTensor in this example. + // TVM accept DLPack compatible DLTensors, so function can be invoked + // as long as we pass correct pointer to DLTensor array. + // + // For more information please refer to dlpack. + // One thing to notice is that DLPack contains alignment requirement for + // the data pointer and TVM takes advantage of that. + // If you plan to use your customized data container, please + // make sure the DLTensor you pass in meet the alignment requirement. + // + DLTensor* x; + DLTensor* y; + int ndim = 1; + int dtype_code = kDLFloat; + int dtype_bits = 32; + int dtype_lanes = 1; + int device_type = kDLCPU; + int device_id = 0; + int64_t shape[1] = {10}; + TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, + device_type, device_id, &x); + TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, + device_type, device_id, &y); + for (int i = 0; i < shape[0]; ++i) { + ((float*)(x->data))[i] = i; + printf("%f\n", ((float*)(x->data))[i]); + } + + // Invoke the function + // PackedFunc is a function that can be invoked via positional argument. + // The signature of the function is specified in tvm.build + TVMValue arg_values[2]; + arg_values[0].v_handle = x; + arg_values[1].v_handle = y; + int type_codes[2] = {kDLFloat, kDLFloat,}; + TVMValue ret_val[1]; + ret_val[0].v_handle = y; + int ret_type_code[1] = {kDLFloat,}; + TVMFuncCall(f, arg_values, type_codes, 1, ret_val, ret_type_code); + + // Print out the output + for (int i = 0; i < shape[0]; ++i) { + /* assert(((float*)(y->data))[i] == (i + 1.0f)); */ + printf("%f vs %f\n", ((float*)(y->data))[i], i + 1.0f); + } + + printf("Finish verification...\n"); + + // Release memory + TVMArrayFree(x); + TVMArrayFree(y); +} + +int main(void) { + // Normally we can directly + TVMModuleHandle mod_dylib; + TVMModLoadFromFile("lib/test_addone_dll.so", "", &mod_dylib); + /* LOG(INFO) << "Verify dynamic loading from test_addone_dll.so"; */ + Verify(mod_dylib, "addone"); + + // For libraries that are directly packed as system lib and linked together with the app + // We can directly use GetSystemLib to get the system wide library. + /* LOG(INFO) << "Verify load function from system lib"; */ + TVMModuleHandle mod_syslib; + TVMFuncGetGlobal("runtime.SystemLib", &mod_syslib); + /* = (*tvm::runtime::Registry::Get("runtime.SystemLib"))(); */ + Verify(mod_syslib, "addonesys"); + + return 0; +} From 2fb54ba1f6b8efddafd129ab2ee90a899b313b16 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 2 Mar 2020 15:16:12 +0800 Subject: [PATCH 22/31] call from c_runtime_api.h --- apps/bundle_deploy_c/Makefile | 14 ++-- apps/bundle_deploy_c/build_model.py | 29 -------- apps/bundle_deploy_c/bundle.c | 89 +++++++++++++++++++++++ apps/bundle_deploy_c/demo.c | 107 ---------------------------- apps/bundle_deploy_c/demo.cc | 3 +- apps/bundle_deploy_c/runtime.c | 10 ++- src/runtime/crt/bundle.c | 59 --------------- src/runtime/crt/crt_backend_api.c | 3 + src/runtime/crt/crt_runtime_api.c | 42 +++++++++++ src/runtime/crt/graph_runtime.c | 1 - src/runtime/crt/graph_runtime.h | 9 ++- src/runtime/crt/packed_func.h | 7 +- 12 files changed, 161 insertions(+), 212 deletions(-) create mode 100644 apps/bundle_deploy_c/bundle.c delete mode 100644 apps/bundle_deploy_c/demo.c delete mode 100644 src/runtime/crt/bundle.c diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index e3e6509df0a9..9cd2701cd924 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -58,9 +58,9 @@ build_dir := build test: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin -$(build_dir)/demo: demo.cc +$(build_dir)/demo: demo.cc ${build_dir}/graph.json.c ${build_dir}/params.bin.c @mkdir -p $(@D) - g++ $(PKG_CXXFLAGS) -o $@ $^ -ldl + g++ $(PKG_CXXFLAGS) -o $@ demo.cc -ldl # Serialize our graph.json file. $(build_dir)/graph.json.c: $(build_dir)/graph.json @@ -70,21 +70,15 @@ $(build_dir)/graph.json.c: $(build_dir)/graph.json $(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ -$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/bridge.c $(build_dir)/cat.bin: build_model.py +$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/cat.bin: build_model.py python3 $< -o $(build_dir) # Build our bundle against the serialized bundle.c API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: runtime.c $(build_dir)/model.o $(build_dir)/bridge.c +$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) -$(build_dir)/graph.json.o: $(build_dir)/graph.json.c - gcc -c ${PKG_CFLAGS} -o $@ $^ - -$(build_dir)/params.bin.o: $(build_dir)/params.bin.c - gcc -c ${PKG_CFLAGS} -o $@ $^ - clean: rm -rf $(build_dir)/bundle.so diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py index d60d144668da..2a1bd175acd6 100644 --- a/apps/bundle_deploy_c/build_model.py +++ b/apps/bundle_deploy_c/build_model.py @@ -46,34 +46,6 @@ def build_module(opts): with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: f_params.write(relay.save_param_dict(params)) -def build_bridge(opts): - build_dir = os.path.abspath(opts.out_dir) - json_data = {} - with open(os.path.join(build_dir, 'graph.json'), 'rt') as fp: - json_data = json.loads(fp.read()) - if json_data == {}: - return - else: - nodes = [node['attrs']['func_name'] for node in json_data['nodes'] if node['op'] == "tvm_op"] - with open(os.path.join(build_dir, 'bridge.c'), 'w') as f_bridge: - f_bridge.write("#include \"../../../src/runtime/crt/packed_func.h\"\n") - f_bridge.write("\n") - f_bridge.write("#define REGISTER_PACKED_FUNC(func_name) \\\n") - f_bridge.write(" do { \\\n") - f_bridge.write(" strcpy(fexecs[idx].name, #func_name ); \\\n") - f_bridge.write(" fexecs[idx].fexec = func_name ; \\\n") - f_bridge.write(" idx ++; \\\n") - f_bridge.write(" } while (0)\n") - f_bridge.write("\n") - for node in nodes: - f_bridge.write("int %s(TVMValue * args, int * arg_type_ids, int num_args, TVMRetValueHandle ret, void * res);\n" % (node,)) - f_bridge.write("\n") - f_bridge.write("void TVMPackedFunc_SetupExecs() {\n") - f_bridge.write(" int32_t idx = 0;\n") - for node in nodes: - f_bridge.write(" REGISTER_PACKED_FUNC(%s);\n" % (node,)) - f_bridge.write("}\n") - def build_inputs(opts): from tvm.contrib import download from PIL import Image @@ -107,5 +79,4 @@ def transform_image(image): opts = parser.parse_args() build_module(opts) - build_bridge(opts) build_inputs(opts) diff --git a/apps/bundle_deploy_c/bundle.c b/apps/bundle_deploy_c/bundle.c new file mode 100644 index 000000000000..c111e3a3a531 --- /dev/null +++ b/apps/bundle_deploy_c/bundle.c @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +#include + +/*! \brief macro to do C API call */ +#define TVM_CCALL(func) \ + do { \ + int ret = (func); \ + if (ret != 0) { \ + fprintf(stderr, "%s: %d: error: %s\n", __FILE__, __LINE__, TVMGetLastError()); \ + exit(ret); \ + } \ + } while (0) + +TVM_DLL void * tvm_runtime_create(const char * json_data, + const char * params_data, + const uint64_t params_size) { + int64_t device_type = kDLCPU; + int64_t device_id = 0; + + TVMByteArray params; + params.data = params_data; + params.size = params_size; + + TVMContext ctx; + ctx.device_type = (DLDeviceType)device_type; + ctx.device_id = device_id; + + // declare pointers + TVMModuleHandle (*SystemLibraryCreate)(); + TVMModuleHandle (*TVMGraphRuntimeCreate)(const char *, const TVMModuleHandle, const TVMContext *); + int (*TVMGraphRuntime_LoadParams)(TVMModuleHandle, const char *, const uint32_t); + + // get pointers + TVM_CCALL(TVMFuncGetGlobal("runtime.SystemLib", (TVMFunctionHandle*)&SystemLibraryCreate)); + TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.create", (TVMFunctionHandle*)&TVMGraphRuntimeCreate)); + + // run modules + TVMModuleHandle mod_syslib = SystemLibraryCreate(); + TVMModuleHandle mod = TVMGraphRuntimeCreate(json_data, mod_syslib, &ctx); + TVM_CCALL(TVMModGetFunction(mod, "load_params", 0, (TVMFunctionHandle*)&TVMGraphRuntime_LoadParams)); + TVMGraphRuntime_LoadParams(mod, params.data, params.size); + + return mod; +} + +TVM_DLL void tvm_runtime_destroy(void * runtime) { + void (*TVMGraphRuntimeRelease)(TVMModuleHandle *); + TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.release", (TVMFunctionHandle*)&TVMGraphRuntimeRelease)); + TVMGraphRuntimeRelease(&runtime); +} + +TVM_DLL void tvm_runtime_set_input(void * runtime, const char * name, DLTensor * tensor) { + void (*TVMGraphRuntime_SetInput)(TVMModuleHandle, const char *, DLTensor*); + TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.set_input", (TVMFunctionHandle*)&TVMGraphRuntime_SetInput)); + TVMGraphRuntime_SetInput(runtime, "data", tensor); +} + +TVM_DLL void tvm_runtime_run(void * runtime) { + void (*TVMGraphRuntime_Run)(TVMModuleHandle runtime); + TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.run", (TVMFunctionHandle*)&TVMGraphRuntime_Run)); + TVMGraphRuntime_Run(runtime); +} + +TVM_DLL void tvm_runtime_get_output(void * runtime, int32_t index, DLTensor * tensor) { + int (*TVMGraphRuntime_GetOutput)(TVMModuleHandle, const int32_t, DLTensor *); + TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.get_output", (TVMFunctionHandle*)&TVMGraphRuntime_GetOutput)); + TVMGraphRuntime_GetOutput(runtime, index, tensor); +} + diff --git a/apps/bundle_deploy_c/demo.c b/apps/bundle_deploy_c/demo.c deleted file mode 100644 index 06eb34163104..000000000000 --- a/apps/bundle_deploy_c/demo.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/*! - * \brief Example code on load and run TVM modules - * \file c_deploy.c - */ -#include - -#include -#include - -void Verify(TVMModuleHandle mod, const char * fname) { - // Get the function from the module. - TVMFunctionHandle f; - TVMModGetFunction(mod, fname, 0, &f); - - /* CHECK(f != nullptr); */ - - // Allocate the DLPack data structures. - // - // Note that we use TVM runtime API to allocate the DLTensor in this example. - // TVM accept DLPack compatible DLTensors, so function can be invoked - // as long as we pass correct pointer to DLTensor array. - // - // For more information please refer to dlpack. - // One thing to notice is that DLPack contains alignment requirement for - // the data pointer and TVM takes advantage of that. - // If you plan to use your customized data container, please - // make sure the DLTensor you pass in meet the alignment requirement. - // - DLTensor* x; - DLTensor* y; - int ndim = 1; - int dtype_code = kDLFloat; - int dtype_bits = 32; - int dtype_lanes = 1; - int device_type = kDLCPU; - int device_id = 0; - int64_t shape[1] = {10}; - TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, - device_type, device_id, &x); - TVMArrayAlloc(shape, ndim, dtype_code, dtype_bits, dtype_lanes, - device_type, device_id, &y); - for (int i = 0; i < shape[0]; ++i) { - ((float*)(x->data))[i] = i; - printf("%f\n", ((float*)(x->data))[i]); - } - - // Invoke the function - // PackedFunc is a function that can be invoked via positional argument. - // The signature of the function is specified in tvm.build - TVMValue arg_values[2]; - arg_values[0].v_handle = x; - arg_values[1].v_handle = y; - int type_codes[2] = {kDLFloat, kDLFloat,}; - TVMValue ret_val[1]; - ret_val[0].v_handle = y; - int ret_type_code[1] = {kDLFloat,}; - TVMFuncCall(f, arg_values, type_codes, 1, ret_val, ret_type_code); - - // Print out the output - for (int i = 0; i < shape[0]; ++i) { - /* assert(((float*)(y->data))[i] == (i + 1.0f)); */ - printf("%f vs %f\n", ((float*)(y->data))[i], i + 1.0f); - } - - printf("Finish verification...\n"); - - // Release memory - TVMArrayFree(x); - TVMArrayFree(y); -} - -int main(void) { - // Normally we can directly - TVMModuleHandle mod_dylib; - TVMModLoadFromFile("lib/test_addone_dll.so", "", &mod_dylib); - /* LOG(INFO) << "Verify dynamic loading from test_addone_dll.so"; */ - Verify(mod_dylib, "addone"); - - // For libraries that are directly packed as system lib and linked together with the app - // We can directly use GetSystemLib to get the system wide library. - /* LOG(INFO) << "Verify load function from system lib"; */ - TVMModuleHandle mod_syslib; - TVMFuncGetGlobal("runtime.SystemLib", &mod_syslib); - /* = (*tvm::runtime::Registry::Get("runtime.SystemLib"))(); */ - Verify(mod_syslib, "addonesys"); - - return 0; -} diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc index ce7f400d29d4..33105ffa9388 100644 --- a/apps/bundle_deploy_c/demo.cc +++ b/apps/bundle_deploy_c/demo.cc @@ -18,9 +18,9 @@ */ #include + #include #include //dlopen -#include #include #include #include @@ -62,6 +62,7 @@ int main(int argc, char **argv) { input.shape = input_shape.data(); input.strides = nullptr; input.byte_offset = 0; + getFunc(bundle, "tvm_runtime_set_input")( handle, "data", &input); diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index d64927ed7575..f2590c7ed1c1 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -23,10 +23,18 @@ #define _POSIX_C_SOURCE 200809L #endif +#define TVM_CRT_MAX_NDIM 6 +#define TVM_CRT_MAX_ARGS 10 +#define GRAPH_RUNTIME_NODE_MAX_INPUTS 300 +#define GRAPH_RUNTIME_MAX_CONTEXTS 1 +#define GRAPH_RUNTIME_MAX_NODES 400 +#define GRAPH_RUNTIME_MAX_INPUT_NODES 300 +#define GRAPH_RUNTIME_MAX_NODE_ROW_PTR 300 +#define GRAPH_RUNTIME_MAX_OUTPUTS 300 + #include "../../src/runtime/crt/crt_runtime_api.c" #include "../../src/runtime/crt/crt_backend_api.c" #include "../../src/runtime/crt/graph_runtime.c" #include "../../src/runtime/crt/load_json.c" #include "../../src/runtime/crt/ndarray.c" -#include "../../src/runtime/crt/bundle.c" diff --git a/src/runtime/crt/bundle.c b/src/runtime/crt/bundle.c deleted file mode 100644 index ac6be10e15bf..000000000000 --- a/src/runtime/crt/bundle.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 "graph_runtime.h" - -TVM_DLL TVMGraphRuntime * tvm_runtime_create(const char * json_data, - const char * params_data, - const uint64_t params_size) { - int64_t device_type = kDLCPU; - int64_t device_id = 0; - - TVMByteArray params; - params.data = params_data; - params.size = params_size; - - TVMContext ctx; - ctx.device_type = (DLDeviceType)device_type; - ctx.device_id = device_id; - TVMGraphRuntime * runtime = TVMGraphRuntimeCreate(json_data, 0, &ctx); - - runtime->LoadParams(runtime, params.data, params.size); - - return runtime; -} - -TVM_DLL void tvm_runtime_destroy(TVMGraphRuntime * runtime) { - TVMGraphRuntimeRelease(&runtime); -} - -TVM_DLL void tvm_runtime_set_input(TVMGraphRuntime * runtime, const char * name, - DLTensor * tensor) { - runtime->SetInput(runtime, "data", tensor); -} - -TVM_DLL void tvm_runtime_run(TVMGraphRuntime * runtime) { - runtime->Run(runtime); -} - -TVM_DLL void tvm_runtime_get_output(TVMGraphRuntime * runtime, int32_t index, - DLTensor * tensor) { - runtime->GetOutput(runtime, index, tensor); -} - diff --git a/src/runtime/crt/crt_backend_api.c b/src/runtime/crt/crt_backend_api.c index 7eff78d5e5aa..e011e47b2576 100644 --- a/src/runtime/crt/crt_backend_api.c +++ b/src/runtime/crt/crt_backend_api.c @@ -52,5 +52,8 @@ int TVMBackendParallelLaunch(FTVMParallelLambda flambda, void* cdata, int num_ta } int TVMBackendRegisterSystemLibSymbol(const char* name, void* ptr) { + snprintf(g_fexecs[g_fexecs_count].name, sizeof(g_fexecs[g_fexecs_count].name), name); + g_fexecs[g_fexecs_count].fexec = ptr; + g_fexecs_count++; return 0; } diff --git a/src/runtime/crt/crt_runtime_api.c b/src/runtime/crt/crt_runtime_api.c index c153c0767e21..07c467b14be9 100644 --- a/src/runtime/crt/crt_runtime_api.c +++ b/src/runtime/crt/crt_runtime_api.c @@ -25,6 +25,8 @@ #include #include "ndarray.h" +#include "graph_runtime.h" +#include "packed_func.h" // Handle internal errors @@ -64,3 +66,43 @@ int TVMArrayFree(TVMArrayHandle handle) { arr.dl_tensor = *handle; return TVMNDArray_Release(&arr); } + +void * SystemLibraryCreate() { + return 0; +} + +int TVMModGetFunction(TVMModuleHandle mod, + const char* func_name, + int query_imports, + TVMFunctionHandle *out) { + int status = 0; + if (!strcmp(func_name, "load_params")) { + *out = &TVMGraphRuntime_LoadParams; + } else { + status -1; + } + return status; +} + +int TVMFuncGetGlobal(const char* name, TVMFunctionHandle* out) { + int status = 0; + if (!strcmp(name, "tvm.graph_runtime.create")){ + *out = &TVMGraphRuntimeCreate; + } else if (!strcmp(name, "tvm.graph_runtime.set_input")){ + *out = &TVMGraphRuntime_SetInput; + } else if (!strcmp(name, "tvm.graph_runtime.run")){ + *out = &TVMGraphRuntime_Run; + } else if (!strcmp(name, "tvm.graph_runtime.get_output")){ + *out = &TVMGraphRuntime_GetOutput; + } else if (!strcmp(name, "tvm.graph_runtime.release")){ + *out = &TVMGraphRuntimeRelease; + } else if (!strcmp(name, "runtime.SystemLib")){ + *out = &SystemLibraryCreate; + } else { + char msg[200]; + snprintf(msg, sizeof(msg), "fail to get global: name=%s", name); + TVMAPISetLastError(msg); + status = -1; + } + return status; +} diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index 71a5bac46367..bfbedb22e1b5 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -647,7 +647,6 @@ void TVMGraphRuntime_Init(TVMGraphRuntime * runtime, const char * graph_json, runtime->Load(runtime, &reader); runtime->ctxs[0] = ctxs[0]; runtime->SetupStorage(runtime); - TVMPackedFunc_SetupExecs(); runtime->SetupOpExecs(runtime); JSONReader_Release(&reader); } diff --git a/src/runtime/crt/graph_runtime.h b/src/runtime/crt/graph_runtime.h index fda08387211a..7fe395c5b09c 100644 --- a/src/runtime/crt/graph_runtime.h +++ b/src/runtime/crt/graph_runtime.h @@ -189,9 +189,16 @@ typedef struct TVMGraphRuntime { uint32_t op_execs_count; } TVMGraphRuntime; +// public functions TVMGraphRuntime * TVMGraphRuntimeCreate(const char * sym_json, const TVMModule * m, const TVMContext * ctxs); - void TVMGraphRuntimeRelease(TVMGraphRuntime ** runtime); +// private functions +void TVMGraphRuntime_SetInput(TVMGraphRuntime * runtime, const char * name, DLTensor* data_in); +int TVMGraphRuntime_LoadParams(TVMGraphRuntime * runtime, const char * param_blob, + const uint32_t param_size); +void TVMGraphRuntime_Run(TVMGraphRuntime * runtime); +int TVMGraphRuntime_GetOutput(TVMGraphRuntime * runtime, const int32_t idx, DLTensor * out); + #endif // TVM_RUNTIME_CRT_GRAPH_RUNTIME_H_ diff --git a/src/runtime/crt/packed_func.h b/src/runtime/crt/packed_func.h index 6cec942f550c..21370b69c8c0 100644 --- a/src/runtime/crt/packed_func.h +++ b/src/runtime/crt/packed_func.h @@ -112,7 +112,8 @@ static inline void TVMPackedFunc_SetArgs(TVMPackedFunc * pf, const TVMArgs * arg memcpy(&(pf->args), args, sizeof(TVMArgs)); } -TVMPackedFunc fexecs[GRAPH_RUNTIME_MAX_NODES]; +TVMPackedFunc g_fexecs[GRAPH_RUNTIME_MAX_NODES]; +uint32_t g_fexecs_count = 0; void TVMPackedFunc_SetupExecs(); @@ -127,8 +128,8 @@ static inline void TVMModule_GetFunction(const char * name, TVMPackedFunc * pf) pf->SetArgs = TVMPackedFunc_SetArgs; pf->fexec = &TVMNoOperation; for (idx = 0; idx < GRAPH_RUNTIME_MAX_NODES; idx++) { - if (!strcmp(fexecs[idx].name, name)) { - pf->fexec = fexecs[idx].fexec; + if (!strcmp(g_fexecs[idx].name, name)) { + pf->fexec = g_fexecs[idx].fexec; break; } } From 441da25fd42cc1ef460c00e51c9ba4481eb252f2 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 2 Mar 2020 15:22:52 +0800 Subject: [PATCH 23/31] clean up --- apps/bundle_deploy_c/Makefile | 28 +++------------------------- apps/bundle_deploy_c/runtime.c | 2 ++ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile index 9cd2701cd924..c78321ab08f5 100644 --- a/apps/bundle_deploy_c/Makefile +++ b/apps/bundle_deploy_c/Makefile @@ -17,39 +17,17 @@ # Makefile Example to bundle TVM modules. -# Preserve debug feature for MISRA C -DEBUG = 0 - -# Configure runtime -MAX_NDIM = 6 -MAX_ARGS = 10 -GRAPH_RUNTIME_NODE_MAX_INPUTS = 300 -GRAPH_RUNTIME_MAX_CONTEXTS = 1 -GRAPH_RUNTIME_MAX_NODES = 400 -GRAPH_RUNTIME_MAX_INPUT_NODES = 300 -GRAPH_RUNTIME_MAX_NODE_ROW_PTR = 300 -GRAPH_RUNTIME_MAX_OUTPUTS = 300 - # Setup build environment TVM_ROOT=$(shell cd ../..; pwd) DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CXXFLAGS = -std=c++14 -O0 -g -fPIC \ +PKG_CXXFLAGS = -std=c++14 -O2 -fPIC \ -I${TVM_ROOT}/include \ -I${DMLC_CORE}/include \ -I${TVM_ROOT}/3rdparty/dlpack/include -PKG_CFLAGS = -std=c99 -O0 -g -fPIC \ +PKG_CFLAGS = -std=c99 -O2 -fPIC \ -I${TVM_ROOT}/include \ -I${DMLC_CORE}/include \ - -I${TVM_ROOT}/3rdparty/dlpack/include \ - -DTVM_CRT_DEBUG=${DEBUG} \ - -DTVM_CRT_MAX_NDIM=${MAX_NDIM} \ - -DTVM_CRT_MAX_ARGS=${MAX_ARGS} \ - -DGRAPH_RUNTIME_NODE_MAX_INPUTS=${GRAPH_RUNTIME_NODE_MAX_INPUTS} \ - -DGRAPH_RUNTIME_MAX_CONTEXTS=${GRAPH_RUNTIME_MAX_CONTEXTS} \ - -DGRAPH_RUNTIME_MAX_NODES=${GRAPH_RUNTIME_MAX_NODES} \ - -DGRAPH_RUNTIME_MAX_INPUT_NODES=${GRAPH_RUNTIME_MAX_INPUT_NODES} \ - -DGRAPH_RUNTIME_MAX_NODE_ROW_PTR=${GRAPH_RUNTIME_MAX_NODE_ROW_PTR} \ - -DGRAPH_RUNTIME_MAX_OUTPUTS=${GRAPH_RUNTIME_MAX_OUTPUTS} + -I${TVM_ROOT}/3rdparty/dlpack/include PKG_LDFLAGS = -pthread diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy_c/runtime.c index f2590c7ed1c1..ec2a823f98c3 100644 --- a/apps/bundle_deploy_c/runtime.c +++ b/apps/bundle_deploy_c/runtime.c @@ -23,6 +23,8 @@ #define _POSIX_C_SOURCE 200809L #endif +#define TVM_CRT_DEBUG 0 + #define TVM_CRT_MAX_NDIM 6 #define TVM_CRT_MAX_ARGS 10 #define GRAPH_RUNTIME_NODE_MAX_INPUTS 300 From d0eb7632ffa63eab9a5b6b698baa4a1a51014a81 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 2 Mar 2020 15:26:28 +0800 Subject: [PATCH 24/31] lint --- src/runtime/crt/crt_runtime_api.c | 12 ++++++------ src/runtime/crt/ndarray.h | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/runtime/crt/crt_runtime_api.c b/src/runtime/crt/crt_runtime_api.c index 07c467b14be9..433ae8ad3457 100644 --- a/src/runtime/crt/crt_runtime_api.c +++ b/src/runtime/crt/crt_runtime_api.c @@ -86,17 +86,17 @@ int TVMModGetFunction(TVMModuleHandle mod, int TVMFuncGetGlobal(const char* name, TVMFunctionHandle* out) { int status = 0; - if (!strcmp(name, "tvm.graph_runtime.create")){ + if (!strcmp(name, "tvm.graph_runtime.create")) { *out = &TVMGraphRuntimeCreate; - } else if (!strcmp(name, "tvm.graph_runtime.set_input")){ + } else if (!strcmp(name, "tvm.graph_runtime.set_input")) { *out = &TVMGraphRuntime_SetInput; - } else if (!strcmp(name, "tvm.graph_runtime.run")){ + } else if (!strcmp(name, "tvm.graph_runtime.run")) { *out = &TVMGraphRuntime_Run; - } else if (!strcmp(name, "tvm.graph_runtime.get_output")){ + } else if (!strcmp(name, "tvm.graph_runtime.get_output")) { *out = &TVMGraphRuntime_GetOutput; - } else if (!strcmp(name, "tvm.graph_runtime.release")){ + } else if (!strcmp(name, "tvm.graph_runtime.release")) { *out = &TVMGraphRuntimeRelease; - } else if (!strcmp(name, "runtime.SystemLib")){ + } else if (!strcmp(name, "runtime.SystemLib")) { *out = &SystemLibraryCreate; } else { char msg[200]; diff --git a/src/runtime/crt/ndarray.h b/src/runtime/crt/ndarray.h index 009a1a174d95..dde23ca6cd41 100644 --- a/src/runtime/crt/ndarray.h +++ b/src/runtime/crt/ndarray.h @@ -42,9 +42,11 @@ typedef struct TVMNDArray { DLTensor dl_tensor; } TVMNDArray; -TVMNDArray TVMNDArray_Create(uint32_t ndim, const tvm_index_t * shape, DLDataType dtype, DLContext ctx); +TVMNDArray TVMNDArray_Create(uint32_t ndim, const tvm_index_t * shape, + DLDataType dtype, DLContext ctx); -TVMNDArray TVMNDArray_Empty(uint32_t ndim, const tvm_index_t * shape, DLDataType dtype, DLContext ctx); +TVMNDArray TVMNDArray_Empty(uint32_t ndim, const tvm_index_t * shape, + DLDataType dtype, DLContext ctx); int TVMNDArray_Load(TVMNDArray * ret, const char ** strm); From 945018d2a6f0ec724bfe807fa6b3c656530e1ded Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 5 Mar 2020 14:24:24 +0800 Subject: [PATCH 25/31] merge into apps/bundle_deploy directory Change-Id: I51904db81b8589e65d107d8ca77b47452e3812b5 --- apps/bundle_deploy/Makefile | 41 ++++--- apps/bundle_deploy/README.md | 9 +- apps/bundle_deploy/build_model.py | 43 ++++++-- .../bundle.c | 0 apps/bundle_deploy/bundle.cc | 10 +- apps/bundle_deploy/demo.cc | 63 ++++++++--- .../runtime.c | 0 apps/bundle_deploy_c/Makefile | 64 ----------- apps/bundle_deploy_c/README.md | 53 ---------- apps/bundle_deploy_c/build_model.py | 82 -------------- apps/bundle_deploy_c/demo.cc | 100 ------------------ 11 files changed, 119 insertions(+), 346 deletions(-) rename apps/{bundle_deploy_c => bundle_deploy}/bundle.c (100%) rename apps/{bundle_deploy_c => bundle_deploy}/runtime.c (100%) delete mode 100644 apps/bundle_deploy_c/Makefile delete mode 100644 apps/bundle_deploy_c/README.md delete mode 100644 apps/bundle_deploy_c/build_model.py delete mode 100644 apps/bundle_deploy_c/demo.cc diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 57e484379a4e..6421fb125c05 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -17,40 +17,53 @@ # Makefile Example to bundle TVM modules. +# Setup build environment TVM_ROOT=$(shell cd ../..; pwd) DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CFLAGS = -std=c++14 -O2 -fPIC\ - -I${TVM_ROOT}/include\ - -I${DMLC_CORE}/include\ +PKG_CXXFLAGS = -std=c++14 -O0 -g -fPIC \ + -I${TVM_ROOT}/include \ + -I${DMLC_CORE}/include \ + -I${TVM_ROOT}/3rdparty/dlpack/include +PKG_CFLAGS = -std=c99 -O0 -g -fPIC \ + -I${TVM_ROOT}/include \ + -I${DMLC_CORE}/include \ -I${TVM_ROOT}/3rdparty/dlpack/include PKG_LDFLAGS = -pthread build_dir := build -test: $(build_dir)/demo $(build_dir)/bundle.so - $(build_dir)/demo $(build_dir)/bundle.so +demo: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/bundle_c.so $(build_dir)/cat.bin + $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin + $(build_dir)/demo $(build_dir)/bundle_c.so $(build_dir)/cat.bin -$(build_dir)/demo: demo.cc +$(build_dir)/demo: demo.cc ${build_dir}/graph.json.c ${build_dir}/params.bin.c @mkdir -p $(@D) - $(CXX) $(PKG_CFLAGS) -o $@ $^ -ldl + g++ $(PKG_CXXFLAGS) -o $@ demo.cc -ldl # Serialize our graph.json file. -$(build_dir)/graph.json.cc: $(build_dir)/graph.json +$(build_dir)/graph.json.c: $(build_dir)/graph.json xxd -i $^ > $@ # Serialize our params.bin file. -$(build_dir)/params.bin.cc: $(build_dir)/params.bin +$(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ -$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin: build_model.py +$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/cat.bin: build_model.py python3 $< -o $(build_dir) -# Build our bundle against the serialized bundle.cc API, the runtime.cc API, and +# Build our bundle against the serialized bundle.c API, the runtime.cc API, and # the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.cc runtime.cc $(build_dir)/model.o $(build_dir)/graph.json.cc $(build_dir)/params.bin.cc +$(build_dir)/bundle.so: bundle.cc runtime.cc $(build_dir)/model.o + @mkdir -p $(@D) + g++ -shared $(PKG_CXXFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + +$(build_dir)/bundle_c.so: bundle.c runtime.c $(build_dir)/model.o @mkdir -p $(@D) - $(CXX) -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) clean: - rm -r $(build_dir) + rm -rf $(build_dir)/bundle.so + +cleanall: + rm -rf $(build_dir) diff --git a/apps/bundle_deploy/README.md b/apps/bundle_deploy/README.md index 6be9c4f91340..676ae7d9e6c9 100644 --- a/apps/bundle_deploy/README.md +++ b/apps/bundle_deploy/README.md @@ -45,9 +45,10 @@ make demo This will: - Download the mobilenet0.25 model from the MXNet Gluon Model Zoo -- Compile the model with NNVM +- Compile the model with Relay - Build a `bundle.so` shared object containing the model specification and parameters -- Build a `demo` executable that `dlopen`'s `bundle.so`, instantiates the - contained graph runtime, and invokes the `GraphRuntime::Run` function on a - random input, then prints the output tensor to `stderr`. +- Build a `demo` executable that `dlopen`'s `bundle.so` (or `bundle_c.so` in + terms of the MISRA-C runtime), instantiates the contained graph runtime, + and invokes the `GraphRuntime::Run` function on a cat image, then prints + the output results. diff --git a/apps/bundle_deploy/build_model.py b/apps/bundle_deploy/build_model.py index de9e73522ca2..2a1bd175acd6 100644 --- a/apps/bundle_deploy/build_model.py +++ b/apps/bundle_deploy/build_model.py @@ -21,15 +21,9 @@ from tvm import relay import tvm import logging +import json - -def main(): - logging.basicConfig(level=logging.INFO) - - parser = argparse.ArgumentParser() - parser.add_argument('-o', '--out-dir', default='.') - opts = parser.parse_args() - +def build_module(opts): dshape = (1, 3, 224, 224) from mxnet.gluon.model_zoo.vision import get_model block = get_model('mobilenet0.25', pretrained=True) @@ -52,6 +46,37 @@ def main(): with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: f_params.write(relay.save_param_dict(params)) +def build_inputs(opts): + from tvm.contrib import download + from PIL import Image + import numpy as np + + build_dir = os.path.abspath(opts.out_dir) + + # Download test image + image_url = 'https://homes.cs.washington.edu/~moreau/media/vta/cat.jpg' + image_fn = os.path.join(build_dir, "cat.png") + download.download(image_url, image_fn) + image = Image.open(image_fn).resize((224, 224)) + + def transform_image(image): + image = np.array(image) - np.array([123., 117., 104.]) + image /= np.array([58.395, 57.12, 57.375]) + image = image.transpose((2, 0, 1)) + image = image[np.newaxis, :] + return image + + x = transform_image(image) + print('x', x.shape) + with open(os.path.join(build_dir, "cat.bin"), "wb") as fp: + fp.write(x.astype(np.float32).tobytes()) if __name__ == '__main__': - main() + logging.basicConfig(level=logging.INFO) + + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--out-dir', default='.') + opts = parser.parse_args() + + build_module(opts) + build_inputs(opts) diff --git a/apps/bundle_deploy_c/bundle.c b/apps/bundle_deploy/bundle.c similarity index 100% rename from apps/bundle_deploy_c/bundle.c rename to apps/bundle_deploy/bundle.c diff --git a/apps/bundle_deploy/bundle.cc b/apps/bundle_deploy/bundle.cc index 22f8ba300dec..3e5080927db4 100644 --- a/apps/bundle_deploy/bundle.cc +++ b/apps/bundle_deploy/bundle.cc @@ -21,16 +21,14 @@ #include #include -extern unsigned char build_graph_json[]; -extern unsigned int build_graph_json_len; -extern unsigned char build_params_bin[]; -extern unsigned int build_params_bin_len; - #define TVM_BUNDLE_FUNCTION __attribute__((visibility("default"))) extern "C" { -TVM_BUNDLE_FUNCTION void *tvm_runtime_create() { +TVM_BUNDLE_FUNCTION void *tvm_runtime_create(const char * build_graph_json, + const char * build_params_bin, + const uint64_t build_params_bin_len) { + const int build_graph_json_len = strlen(build_graph_json); const std::string json_data(&build_graph_json[0], &build_graph_json[0] + build_graph_json_len); tvm::runtime::Module mod_syslib = diff --git a/apps/bundle_deploy/demo.cc b/apps/bundle_deploy/demo.cc index 325bae780260..34be27958c91 100644 --- a/apps/bundle_deploy/demo.cc +++ b/apps/bundle_deploy/demo.cc @@ -17,13 +17,17 @@ * under the License. */ -#include "tvm/runtime/c_runtime_api.h" +#include + #include #include //dlopen -#include #include #include #include +#include + +#include "build/graph.json.c" +#include "build/params.bin.c" template auto getFunc(void *bundle, const char *name) { dlerror(); @@ -34,39 +38,50 @@ template auto getFunc(void *bundle, const char *name) { } int main(int argc, char **argv) { - assert(argc == 2 && "Usage: demo "); + assert(argc == 3 && "Usage: demo "); auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); assert(bundle); - auto *handle = getFunc(bundle, "tvm_runtime_create")(); + char * json_data = reinterpret_cast(build_graph_json); + char * params_data = reinterpret_cast(build_params_bin); + uint64_t params_size = build_params_bin_len; - std::vector input_storage(1 * 3 * 224 * 224); - std::mt19937 gen(0); - for (auto &e : input_storage) { - e = std::uniform_real_distribution(0.0, 1.0)(gen); - } + struct timeval t0, t1, t2, t3, t4, t5; + gettimeofday(&t0, 0); + + auto *handle = getFunc(bundle, "tvm_runtime_create")( + json_data, params_data, params_size); + gettimeofday(&t1, 0); + + float input_storage[1 * 3 * 224 * 224]; + FILE * fp = fopen(argv[2], "rb"); + fread(input_storage, 3 * 224 * 224, 4, fp); + fclose(fp); std::vector input_shape = {1, 3, 224, 224}; DLTensor input; - input.data = input_storage.data(); + input.data = input_storage; input.ctx = DLContext{kDLCPU, 0}; input.ndim = 4; input.dtype = DLDataType{kDLFloat, 32, 1}; input.shape = input_shape.data(); input.strides = nullptr; input.byte_offset = 0; + getFunc(bundle, "tvm_runtime_set_input")( handle, "data", &input); + gettimeofday(&t2, 0); auto *ftvm_runtime_run = (auto (*)(void *)->void)dlsym(bundle, "tvm_runtime_run"); assert(!dlerror()); ftvm_runtime_run(handle); + gettimeofday(&t3, 0); - std::vector output_storage(1000); + float output_storage[1000]; std::vector output_shape = {1, 1000}; DLTensor output; - output.data = output_storage.data(); + output.data = output_storage; output.ctx = DLContext{kDLCPU, 0}; output.ndim = 2; output.dtype = DLDataType{kDLFloat, 32, 1}; @@ -76,10 +91,30 @@ int main(int argc, char **argv) { getFunc(bundle, "tvm_runtime_get_output")( handle, 0, &output); - for (auto i = 0; i < output_storage.size(); ++i) { - std::cerr << "output[" << i << "]: " << output_storage[i] << std::endl; + gettimeofday(&t4, 0); + + float max_iter = -std::numeric_limits::max(); + int32_t max_index = -1; + for (auto i = 0; i < 1000; ++i) { + if (output_storage[i] > max_iter) { + max_iter = output_storage[i]; + max_index = i; + } } + getFunc(bundle, "tvm_runtime_destroy")(handle); + gettimeofday(&t5, 0); + + printf("The maximum position in output vector is: %d, with max-value %f.\n", + max_index, max_iter); + printf("timing: %.2f ms (create), %.2f ms (set_input), %.2f ms (run), " + "%.2f ms (get_output), %.2f ms (destroy)\n", + (t1.tv_sec-t0.tv_sec)*1000000 + (t1.tv_usec-t0.tv_usec)/1000.f, + (t2.tv_sec-t1.tv_sec)*1000000 + (t2.tv_usec-t1.tv_usec)/1000.f, + (t3.tv_sec-t2.tv_sec)*1000000 + (t3.tv_usec-t2.tv_usec)/1000.f, + (t4.tv_sec-t3.tv_sec)*1000000 + (t4.tv_usec-t3.tv_usec)/1000.f, + (t5.tv_sec-t4.tv_sec)*1000000 + (t5.tv_usec-t4.tv_usec)/1000.f); dlclose(bundle); + return 0; } diff --git a/apps/bundle_deploy_c/runtime.c b/apps/bundle_deploy/runtime.c similarity index 100% rename from apps/bundle_deploy_c/runtime.c rename to apps/bundle_deploy/runtime.c diff --git a/apps/bundle_deploy_c/Makefile b/apps/bundle_deploy_c/Makefile deleted file mode 100644 index c78321ab08f5..000000000000 --- a/apps/bundle_deploy_c/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. - -# Makefile Example to bundle TVM modules. - -# Setup build environment -TVM_ROOT=$(shell cd ../..; pwd) -DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CXXFLAGS = -std=c++14 -O2 -fPIC \ - -I${TVM_ROOT}/include \ - -I${DMLC_CORE}/include \ - -I${TVM_ROOT}/3rdparty/dlpack/include -PKG_CFLAGS = -std=c99 -O2 -fPIC \ - -I${TVM_ROOT}/include \ - -I${DMLC_CORE}/include \ - -I${TVM_ROOT}/3rdparty/dlpack/include - -PKG_LDFLAGS = -pthread - -build_dir := build - -test: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin - $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin - -$(build_dir)/demo: demo.cc ${build_dir}/graph.json.c ${build_dir}/params.bin.c - @mkdir -p $(@D) - g++ $(PKG_CXXFLAGS) -o $@ demo.cc -ldl - -# Serialize our graph.json file. -$(build_dir)/graph.json.c: $(build_dir)/graph.json - xxd -i $^ > $@ - -# Serialize our params.bin file. -$(build_dir)/params.bin.c: $(build_dir)/params.bin - xxd -i $^ > $@ - -$(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/cat.bin: build_model.py - python3 $< -o $(build_dir) - -# Build our bundle against the serialized bundle.c API, the runtime.cc API, and -# the serialized graph.json and params.bin -$(build_dir)/bundle.so: bundle.c runtime.c $(build_dir)/model.o - @mkdir -p $(@D) - gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) - -clean: - rm -rf $(build_dir)/bundle.so - -cleanall: - rm -rf $(build_dir) diff --git a/apps/bundle_deploy_c/README.md b/apps/bundle_deploy_c/README.md deleted file mode 100644 index 6be9c4f91340..000000000000 --- a/apps/bundle_deploy_c/README.md +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - -How to Bundle TVM Modules -========================= - -This folder contains an example on how to bundle a TVM module (with the required -interpreter runtime modules such as `runtime::GraphRuntime`, the graph JSON, and -the params) into a single, self-contained shared object (`bundle.so`) which -exposes a C API wrapping the appropriate `runtime::GraphRuntime` instance. - -This is useful for cases where we'd like to avoid deploying the TVM runtime -components to the target host in advance - instead, we simply deploy the bundled -shared-object to the host, which embeds both the model and the runtime -components. The bundle should only depend on libc/libc++. - -It also contains an example code (`demo.cc`) to load this shared object and -invoke the packaged TVM model instance. This is a dependency-free binary that -uses the functionality packaged in `bundle.so` (which means that `bundle.so` can -be deployed lazily at runtime, instead of at compile time) to invoke TVM -functionality. - -Type the following command to run the sample code under the current folder, -after building TVM first. - -```bash -make demo -``` - -This will: - -- Download the mobilenet0.25 model from the MXNet Gluon Model Zoo -- Compile the model with NNVM -- Build a `bundle.so` shared object containing the model specification and - parameters -- Build a `demo` executable that `dlopen`'s `bundle.so`, instantiates the - contained graph runtime, and invokes the `GraphRuntime::Run` function on a - random input, then prints the output tensor to `stderr`. diff --git a/apps/bundle_deploy_c/build_model.py b/apps/bundle_deploy_c/build_model.py deleted file mode 100644 index 2a1bd175acd6..000000000000 --- a/apps/bundle_deploy_c/build_model.py +++ /dev/null @@ -1,82 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -"""Creates a simple TVM modules.""" - -import argparse -import os -from tvm import relay -import tvm -import logging -import json - -def build_module(opts): - dshape = (1, 3, 224, 224) - from mxnet.gluon.model_zoo.vision import get_model - block = get_model('mobilenet0.25', pretrained=True) - shape_dict = {'data': dshape} - mod, params = relay.frontend.from_mxnet(block, shape_dict) - func = mod["main"] - func = relay.Function(func.params, relay.nn.softmax(func.body), None, func.type_params, func.attrs) - - with relay.build_config(opt_level=3): - graph, lib, params = relay.build( - func, 'llvm --system-lib', params=params) - - build_dir = os.path.abspath(opts.out_dir) - if not os.path.isdir(build_dir): - os.makedirs(build_dir) - - lib.save(os.path.join(build_dir, 'model.o')) - with open(os.path.join(build_dir, 'graph.json'), 'w') as f_graph_json: - f_graph_json.write(graph) - with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: - f_params.write(relay.save_param_dict(params)) - -def build_inputs(opts): - from tvm.contrib import download - from PIL import Image - import numpy as np - - build_dir = os.path.abspath(opts.out_dir) - - # Download test image - image_url = 'https://homes.cs.washington.edu/~moreau/media/vta/cat.jpg' - image_fn = os.path.join(build_dir, "cat.png") - download.download(image_url, image_fn) - image = Image.open(image_fn).resize((224, 224)) - - def transform_image(image): - image = np.array(image) - np.array([123., 117., 104.]) - image /= np.array([58.395, 57.12, 57.375]) - image = image.transpose((2, 0, 1)) - image = image[np.newaxis, :] - return image - - x = transform_image(image) - print('x', x.shape) - with open(os.path.join(build_dir, "cat.bin"), "wb") as fp: - fp.write(x.astype(np.float32).tobytes()) - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - - parser = argparse.ArgumentParser() - parser.add_argument('-o', '--out-dir', default='.') - opts = parser.parse_args() - - build_module(opts) - build_inputs(opts) diff --git a/apps/bundle_deploy_c/demo.cc b/apps/bundle_deploy_c/demo.cc deleted file mode 100644 index 33105ffa9388..000000000000 --- a/apps/bundle_deploy_c/demo.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 - -#include -#include //dlopen -#include -#include -#include - -#include "build/graph.json.c" -#include "build/params.bin.c" - -template auto getFunc(void *bundle, const char *name) { - dlerror(); - auto *f = - reinterpret_cast::type>(dlsym(bundle, name)); - assert(!dlerror()); - return f; -} - -int main(int argc, char **argv) { - assert(argc == 3 && "Usage: demo "); - auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); - assert(bundle); - - char * json_data = reinterpret_cast(build_graph_json); - char * params_data = reinterpret_cast(build_params_bin); - uint64_t params_size = build_params_bin_len; - - auto *handle = getFunc(bundle, "tvm_runtime_create")( - json_data, params_data, params_size); - - float input_storage[1 * 3 * 224 * 224]; - FILE * fp = fopen(argv[2], "rb"); - fread(input_storage, 3 * 224 * 224, 4, fp); - fclose(fp); - - std::vector input_shape = {1, 3, 224, 224}; - DLTensor input; - input.data = input_storage; - input.ctx = DLContext{kDLCPU, 0}; - input.ndim = 4; - input.dtype = DLDataType{kDLFloat, 32, 1}; - input.shape = input_shape.data(); - input.strides = nullptr; - input.byte_offset = 0; - - getFunc(bundle, "tvm_runtime_set_input")( - handle, "data", &input); - - auto *ftvm_runtime_run = - (auto (*)(void *)->void)dlsym(bundle, "tvm_runtime_run"); - assert(!dlerror()); - ftvm_runtime_run(handle); - - float output_storage[1000]; - std::vector output_shape = {1, 1000}; - DLTensor output; - output.data = output_storage; - output.ctx = DLContext{kDLCPU, 0}; - output.ndim = 2; - output.dtype = DLDataType{kDLFloat, 32, 1}; - output.shape = output_shape.data(); - output.strides = nullptr; - output.byte_offset = 0; - - getFunc(bundle, "tvm_runtime_get_output")( - handle, 0, &output); - float max_iter = -std::numeric_limits::max(); - int32_t max_index = -1; - for (auto i = 0; i < 1000; ++i) { - if (output_storage[i] > max_iter) { - max_iter = output_storage[i]; - max_index = i; - } - } - printf("The maximum position in output vector is: %d, with max-value %f.\n", - max_index, max_iter); - getFunc(bundle, "tvm_runtime_destroy")(handle); - dlclose(bundle); - return 0; -} From a399683e7235270cb04f07e182ac129ca6d2b807 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 5 Mar 2020 14:39:15 +0800 Subject: [PATCH 26/31] make the demo runs in ci Change-Id: I2c24f8b592508833d3555311c2b24d1931f19385 --- tests/scripts/task_python_integration.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/scripts/task_python_integration.sh b/tests/scripts/task_python_integration.sh index 29ffb5f5f92a..6b0c949e5103 100755 --- a/tests/scripts/task_python_integration.sh +++ b/tests/scripts/task_python_integration.sh @@ -30,6 +30,12 @@ find . -type f -path "*.pyc" | xargs rm -f # Test TVM make cython3 +# Test extern package +cd apps/bundle_deploy +rm -rf build +make +cd ../.. + # Test extern package cd apps/extension rm -rf lib From b65b62e9f2c97ddaaa821e86746b4305b65b67f8 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 5 Mar 2020 14:50:31 +0800 Subject: [PATCH 27/31] address review comments Change-Id: I027ddff15c31fb4da0bd0e461427dce619de1f93 --- apps/bundle_deploy/runtime.c | 10 ++++++++++ src/runtime/crt/load_json.c | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/bundle_deploy/runtime.c b/apps/bundle_deploy/runtime.c index ec2a823f98c3..6a53aa15f573 100644 --- a/apps/bundle_deploy/runtime.c +++ b/apps/bundle_deploy/runtime.c @@ -23,15 +23,25 @@ #define _POSIX_C_SOURCE 200809L #endif +/*! Support low-level debugging in MISRA-C runtime */ #define TVM_CRT_DEBUG 0 +/*! Maximum supported dimension in NDArray */ #define TVM_CRT_MAX_NDIM 6 +/*! Maximum supported arguments in generated functions */ #define TVM_CRT_MAX_ARGS 10 + +/*! Maximum inputs in a GraphRuntimeNode */ #define GRAPH_RUNTIME_NODE_MAX_INPUTS 300 +/*! Maximum supported contexts in a GraphRuntime */ #define GRAPH_RUNTIME_MAX_CONTEXTS 1 +/*! Maximum supported nodes in a GraphRuntime */ #define GRAPH_RUNTIME_MAX_NODES 400 +/*! Maximum input nodes in a GraphRuntime */ #define GRAPH_RUNTIME_MAX_INPUT_NODES 300 +/*! Maximum nodes in a GraphRuntime for quick entry indexing */ #define GRAPH_RUNTIME_MAX_NODE_ROW_PTR 300 +/*! Maximum output entries in a GraphRuntime */ #define GRAPH_RUNTIME_MAX_OUTPUTS 300 #include "../../src/runtime/crt/crt_runtime_api.c" diff --git a/src/runtime/crt/load_json.c b/src/runtime/crt/load_json.c index f1f60578abf0..894ab8938a10 100644 --- a/src/runtime/crt/load_json.c +++ b/src/runtime/crt/load_json.c @@ -18,8 +18,8 @@ */ /*! - * \file saveload_json.cc - * \brief Save and load graph to/from JSON file. + * \file load_json.c + * \brief Load graph from JSON file. */ #include "load_json.h" From 682a74be43b5147fd1ca22edefb3f935c979ee18 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 5 Mar 2020 15:57:47 +0800 Subject: [PATCH 28/31] release Change-Id: I5ad5bb8426468aac9fc8d074e56ddea358a7fd91 --- apps/bundle_deploy/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 6421fb125c05..676d9f43c87b 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -20,11 +20,11 @@ # Setup build environment TVM_ROOT=$(shell cd ../..; pwd) DMLC_CORE=${TVM_ROOT}/3rdparty/dmlc-core -PKG_CXXFLAGS = -std=c++14 -O0 -g -fPIC \ +PKG_CXXFLAGS = -std=c++14 -O2 -fPIC \ -I${TVM_ROOT}/include \ -I${DMLC_CORE}/include \ -I${TVM_ROOT}/3rdparty/dlpack/include -PKG_CFLAGS = -std=c99 -O0 -g -fPIC \ +PKG_CFLAGS = -std=c99 -O2 -fPIC \ -I${TVM_ROOT}/include \ -I${DMLC_CORE}/include \ -I${TVM_ROOT}/3rdparty/dlpack/include From 0ee43ca4deb0ab2e78b2e55143825c58bfa5bcc5 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Thu, 5 Mar 2020 16:10:41 +0800 Subject: [PATCH 29/31] fix ci testing Change-Id: Ic2e82fb3051b6c254ef32a964f976b61e3e5fe4d --- tests/scripts/task_python_integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/task_python_integration.sh b/tests/scripts/task_python_integration.sh index 6b0c949e5103..5ec2d0f9790b 100755 --- a/tests/scripts/task_python_integration.sh +++ b/tests/scripts/task_python_integration.sh @@ -19,7 +19,7 @@ set -e set -u -export PYTHONPATH=python:topi/python:apps/extension/python +export PYTHONPATH=`pwd`/python:`pwd`/topi/python:`pwd`/apps/extension/python export LD_LIBRARY_PATH="build:${LD_LIBRARY_PATH:-}" export TVM_BIND_THREADS=0 export TVM_NUM_THREADS=2 From 521f7a0c15c26eb4dc8965acd838772d13c4cdc5 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 9 Mar 2020 11:47:18 +0800 Subject: [PATCH 30/31] add test case for misra c runtime Change-Id: Ie0dfd0ade6be4665b4384db7d260a6c69b35010f --- apps/bundle_deploy/Makefile | 33 ++++++- apps/bundle_deploy/build_model.py | 36 ++++++- apps/bundle_deploy/bundle.c | 2 +- apps/bundle_deploy/test.cc | 121 +++++++++++++++++++++++ src/runtime/crt/graph_runtime.c | 2 +- tests/scripts/task_python_integration.sh | 4 +- 6 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 apps/bundle_deploy/test.cc diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 676d9f43c87b..01af8951624f 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -34,13 +34,21 @@ PKG_LDFLAGS = -pthread build_dir := build demo: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/bundle_c.so $(build_dir)/cat.bin - $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin - $(build_dir)/demo $(build_dir)/bundle_c.so $(build_dir)/cat.bin + TVM_NUM_THREADS=1 $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/cat.bin + TVM_NUM_THREADS=1 $(build_dir)/demo $(build_dir)/bundle_c.so $(build_dir)/cat.bin + +test: $(build_dir)/test $(build_dir)/test_bundle.so $(build_dir)/test_bundle_c.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin + TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin + TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle_c.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin $(build_dir)/demo: demo.cc ${build_dir}/graph.json.c ${build_dir}/params.bin.c @mkdir -p $(@D) g++ $(PKG_CXXFLAGS) -o $@ demo.cc -ldl +$(build_dir)/test: test.cc ${build_dir}/test_graph.json.c ${build_dir}/test_params.bin.c + @mkdir -p $(@D) + g++ $(PKG_CXXFLAGS) -o $@ test.cc -ldl + # Serialize our graph.json file. $(build_dir)/graph.json.c: $(build_dir)/graph.json xxd -i $^ > $@ @@ -49,9 +57,20 @@ $(build_dir)/graph.json.c: $(build_dir)/graph.json $(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ +# Serialize our test_graph.json file. +$(build_dir)/test_graph.json.c: $(build_dir)/test_graph.json + xxd -i $^ > $@ + +# Serialize our test_params.bin file. +$(build_dir)/test_params.bin.c: $(build_dir)/test_params.bin + xxd -i $^ > $@ + $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/cat.bin: build_model.py python3 $< -o $(build_dir) +$(build_dir)/test_model.o $(build_dir)/test_graph.json $(build_dir)/test_params.bin $(build_dir)/test_data.bin $(build_dir)/test_output.bin: build_model.py + python3 $< -o $(build_dir) --test + # Build our bundle against the serialized bundle.c API, the runtime.cc API, and # the serialized graph.json and params.bin $(build_dir)/bundle.so: bundle.cc runtime.cc $(build_dir)/model.o @@ -62,8 +81,16 @@ $(build_dir)/bundle_c.so: bundle.c runtime.c $(build_dir)/model.o @mkdir -p $(@D) gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) +$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model.o + @mkdir -p $(@D) + g++ -shared $(PKG_CXXFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + +$(build_dir)/test_bundle_c.so: bundle.c runtime.c $(build_dir)/test_model.o + @mkdir -p $(@D) + gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) + clean: - rm -rf $(build_dir)/bundle.so + rm -rf $(build_dir)/bundle.so $(build_dir)/bundle_c.so $(build_dir)/test_bundle.so $(build_dir)/test_bundle_c.so cleanall: rm -rf $(build_dir) diff --git a/apps/bundle_deploy/build_model.py b/apps/bundle_deploy/build_model.py index 400d37d33e3b..63d658e6d428 100644 --- a/apps/bundle_deploy/build_model.py +++ b/apps/bundle_deploy/build_model.py @@ -47,6 +47,34 @@ def build_module(opts): with open(os.path.join(build_dir, 'params.bin'), 'wb') as f_params: f_params.write(relay.save_param_dict(params)) +def build_test_module(opts): + import numpy as np + + x = relay.var('x', shape=(10, 5)) + y = relay.var('y', shape=(1, 5)) + z = relay.add(x, y) + func = relay.Function([x, y], z) + x_data = np.random.rand(10, 5).astype('float32') + y_data = np.random.rand(1, 5).astype('float32') + params = {"y": y_data} + graph, lib, params = relay.build( + tvm.IRModule.from_expr(func), "llvm --system-lib", params=params) + + build_dir = os.path.abspath(opts.out_dir) + if not os.path.isdir(build_dir): + os.makedirs(build_dir) + + lib.save(os.path.join(build_dir, 'test_model.o')) + with open(os.path.join(build_dir, 'test_graph.json'), 'w') as f_graph_json: + f_graph_json.write(graph) + with open(os.path.join(build_dir, 'test_params.bin'), 'wb') as f_params: + f_params.write(relay.save_param_dict(params)) + with open(os.path.join(build_dir, "test_data.bin"), "wb") as fp: + fp.write(x_data.astype(np.float32).tobytes()) + x_output = x_data + y_data + with open(os.path.join(build_dir, "test_output.bin"), "wb") as fp: + fp.write(x_output.astype(np.float32).tobytes()) + def build_inputs(opts): from tvm.contrib import download from PIL import Image @@ -77,7 +105,11 @@ def transform_image(image): parser = argparse.ArgumentParser() parser.add_argument('-o', '--out-dir', default='.') + parser.add_argument('-t', '--test', action='store_true') opts = parser.parse_args() - build_module(opts) - build_inputs(opts) + if opts.test: + build_test_module(opts) + else: + build_module(opts) + build_inputs(opts) diff --git a/apps/bundle_deploy/bundle.c b/apps/bundle_deploy/bundle.c index c111e3a3a531..dd24bcbdc049 100644 --- a/apps/bundle_deploy/bundle.c +++ b/apps/bundle_deploy/bundle.c @@ -72,7 +72,7 @@ TVM_DLL void tvm_runtime_destroy(void * runtime) { TVM_DLL void tvm_runtime_set_input(void * runtime, const char * name, DLTensor * tensor) { void (*TVMGraphRuntime_SetInput)(TVMModuleHandle, const char *, DLTensor*); TVM_CCALL(TVMFuncGetGlobal("tvm.graph_runtime.set_input", (TVMFunctionHandle*)&TVMGraphRuntime_SetInput)); - TVMGraphRuntime_SetInput(runtime, "data", tensor); + TVMGraphRuntime_SetInput(runtime, name, tensor); } TVM_DLL void tvm_runtime_run(void * runtime) { diff --git a/apps/bundle_deploy/test.cc b/apps/bundle_deploy/test.cc new file mode 100644 index 000000000000..460701c8a79a --- /dev/null +++ b/apps/bundle_deploy/test.cc @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + +#include +#include //dlopen +#include +#include +#include +#include + +#include "build/test_graph.json.c" +#include "build/test_params.bin.c" + +template auto getFunc(void *bundle, const char *name) { + dlerror(); + auto *f = + reinterpret_cast::type>(dlsym(bundle, name)); + assert(!dlerror()); + return f; +} + +int main(int argc, char **argv) { + assert(argc == 4 && "Usage: test "); + auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); + assert(bundle); + + char * json_data = reinterpret_cast(build_test_graph_json); + char * params_data = reinterpret_cast(build_test_params_bin); + uint64_t params_size = build_test_params_bin_len; + + struct timeval t0, t1, t2, t3, t4, t5; + gettimeofday(&t0, 0); + + auto *handle = getFunc(bundle, "tvm_runtime_create")( + json_data, params_data, params_size); + gettimeofday(&t1, 0); + + float input_storage[10 * 5]; + FILE * fp = fopen(argv[2], "rb"); + fread(input_storage, 10 * 5, 4, fp); + fclose(fp); + + float result_storage[10 * 5]; + fp = fopen(argv[3], "rb"); + fread(result_storage, 10 * 5, 4, fp); + fclose(fp); + + std::vector input_shape = {10, 5}; + DLTensor input; + input.data = input_storage; + input.ctx = DLContext{kDLCPU, 0}; + input.ndim = 2; + input.dtype = DLDataType{kDLFloat, 32, 1}; + input.shape = input_shape.data(); + input.strides = nullptr; + input.byte_offset = 0; + + getFunc(bundle, "tvm_runtime_set_input")( + handle, "x", &input); + gettimeofday(&t2, 0); + + auto *ftvm_runtime_run = + (auto (*)(void *)->void)dlsym(bundle, "tvm_runtime_run"); + assert(!dlerror()); + ftvm_runtime_run(handle); + gettimeofday(&t3, 0); + + float output_storage[10 * 5]; + std::vector output_shape = {10, 5}; + DLTensor output; + output.data = output_storage; + output.ctx = DLContext{kDLCPU, 0}; + output.ndim = 2; + output.dtype = DLDataType{kDLFloat, 32, 1}; + output.shape = output_shape.data(); + output.strides = nullptr; + output.byte_offset = 0; + + getFunc(bundle, "tvm_runtime_get_output")( + handle, 0, &output); + gettimeofday(&t4, 0); + + for (auto i = 0; i < 10 * 5; ++i) { + assert(fabs(output_storage[i] - result_storage[i]) < 1e-5f); + if (fabs(output_storage[i] - result_storage[i]) >= 1e-5f) { + printf("got %f, expected %f\n", output_storage[i], result_storage[i]); + } + } + + getFunc(bundle, "tvm_runtime_destroy")(handle); + gettimeofday(&t5, 0); + + printf("timing: %.2f ms (create), %.2f ms (set_input), %.2f ms (run), " + "%.2f ms (get_output), %.2f ms (destroy)\n", + (t1.tv_sec-t0.tv_sec)*1000000 + (t1.tv_usec-t0.tv_usec)/1000.f, + (t2.tv_sec-t1.tv_sec)*1000000 + (t2.tv_usec-t1.tv_usec)/1000.f, + (t3.tv_sec-t2.tv_sec)*1000000 + (t3.tv_usec-t2.tv_usec)/1000.f, + (t4.tv_sec-t3.tv_sec)*1000000 + (t4.tv_usec-t3.tv_usec)/1000.f, + (t5.tv_sec-t4.tv_sec)*1000000 + (t5.tv_usec-t4.tv_usec)/1000.f); + dlclose(bundle); + + return 0; +} diff --git a/src/runtime/crt/graph_runtime.c b/src/runtime/crt/graph_runtime.c index bfbedb22e1b5..1957d0bead4b 100644 --- a/src/runtime/crt/graph_runtime.c +++ b/src/runtime/crt/graph_runtime.c @@ -364,7 +364,7 @@ int TVMGraphRuntime_GetInputIndex(TVMGraphRuntime * runtime, const char * name) } } if (rv < 0) { - fprintf(stderr, "cannot find \"%s\" among input", name); + fprintf(stderr, "cannot find \"%s\" among input\n", name); } return rv; } diff --git a/tests/scripts/task_python_integration.sh b/tests/scripts/task_python_integration.sh index 5ec2d0f9790b..5c00fd9c8896 100755 --- a/tests/scripts/task_python_integration.sh +++ b/tests/scripts/task_python_integration.sh @@ -30,10 +30,10 @@ find . -type f -path "*.pyc" | xargs rm -f # Test TVM make cython3 -# Test extern package +# Test MISRA-C runtime cd apps/bundle_deploy rm -rf build -make +make test cd ../.. # Test extern package From 1a1b660814e94b675e9dc80cd557f7a8c21679aa Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Mon, 9 Mar 2020 16:59:13 +0800 Subject: [PATCH 31/31] fread files in testing to avoid calling xxd Change-Id: Ie7fbc16b4b0b9509918d986a841f443900813bef --- apps/bundle_deploy/Makefile | 20 ++++++++++---------- apps/bundle_deploy/test.cc | 31 +++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 01af8951624f..bd4053f2911c 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -38,14 +38,14 @@ demo: $(build_dir)/demo $(build_dir)/bundle.so $(build_dir)/bundle_c.so $(build_ TVM_NUM_THREADS=1 $(build_dir)/demo $(build_dir)/bundle_c.so $(build_dir)/cat.bin test: $(build_dir)/test $(build_dir)/test_bundle.so $(build_dir)/test_bundle_c.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin - TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin - TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle_c.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin + TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin $(build_dir)/test_graph.json $(build_dir)/test_params.bin + TVM_NUM_THREADS=1 $(build_dir)/test $(build_dir)/test_bundle_c.so $(build_dir)/test_data.bin $(build_dir)/test_output.bin $(build_dir)/test_graph.json $(build_dir)/test_params.bin $(build_dir)/demo: demo.cc ${build_dir}/graph.json.c ${build_dir}/params.bin.c @mkdir -p $(@D) g++ $(PKG_CXXFLAGS) -o $@ demo.cc -ldl -$(build_dir)/test: test.cc ${build_dir}/test_graph.json.c ${build_dir}/test_params.bin.c +$(build_dir)/test: test.cc ${build_dir}/test_graph.json ${build_dir}/test_params.bin @mkdir -p $(@D) g++ $(PKG_CXXFLAGS) -o $@ test.cc -ldl @@ -57,13 +57,13 @@ $(build_dir)/graph.json.c: $(build_dir)/graph.json $(build_dir)/params.bin.c: $(build_dir)/params.bin xxd -i $^ > $@ -# Serialize our test_graph.json file. -$(build_dir)/test_graph.json.c: $(build_dir)/test_graph.json - xxd -i $^ > $@ - -# Serialize our test_params.bin file. -$(build_dir)/test_params.bin.c: $(build_dir)/test_params.bin - xxd -i $^ > $@ +# # Serialize our test_graph.json file. +# $(build_dir)/test_graph.json.c: $(build_dir)/test_graph.json +# xxd -i $^ > $@ +# +# # Serialize our test_params.bin file. +# $(build_dir)/test_params.bin.c: $(build_dir)/test_params.bin +# xxd -i $^ > $@ $(build_dir)/model.o $(build_dir)/graph.json $(build_dir)/params.bin $(build_dir)/cat.bin: build_model.py python3 $< -o $(build_dir) diff --git a/apps/bundle_deploy/test.cc b/apps/bundle_deploy/test.cc index 460701c8a79a..643f1adff320 100644 --- a/apps/bundle_deploy/test.cc +++ b/apps/bundle_deploy/test.cc @@ -25,9 +25,7 @@ #include #include #include - -#include "build/test_graph.json.c" -#include "build/test_params.bin.c" +#include template auto getFunc(void *bundle, const char *name) { dlerror(); @@ -38,13 +36,27 @@ template auto getFunc(void *bundle, const char *name) { } int main(int argc, char **argv) { - assert(argc == 4 && "Usage: test "); + assert(argc == 6 && "Usage: test "); auto *bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL); assert(bundle); - char * json_data = reinterpret_cast(build_test_graph_json); - char * params_data = reinterpret_cast(build_test_params_bin); - uint64_t params_size = build_test_params_bin_len; + struct stat st; + char * json_data; + char * params_data; + uint64_t params_size; + + FILE * fp = fopen(argv[4], "rb"); + stat(argv[4], &st); + json_data = (char*)malloc(st.st_size); + fread(json_data, st.st_size, 1, fp); + fclose(fp); + + fp = fopen(argv[5], "rb"); + stat(argv[5], &st); + params_data = (char*)malloc(st.st_size); + fread(params_data, st.st_size, 1, fp); + params_size = st.st_size; + fclose(fp); struct timeval t0, t1, t2, t3, t4, t5; gettimeofday(&t0, 0); @@ -54,7 +66,7 @@ int main(int argc, char **argv) { gettimeofday(&t1, 0); float input_storage[10 * 5]; - FILE * fp = fopen(argv[2], "rb"); + fp = fopen(argv[2], "rb"); fread(input_storage, 10 * 5, 4, fp); fclose(fp); @@ -115,6 +127,9 @@ int main(int argc, char **argv) { (t3.tv_sec-t2.tv_sec)*1000000 + (t3.tv_usec-t2.tv_usec)/1000.f, (t4.tv_sec-t3.tv_sec)*1000000 + (t4.tv_usec-t3.tv_usec)/1000.f, (t5.tv_sec-t4.tv_sec)*1000000 + (t5.tv_usec-t4.tv_usec)/1000.f); + + free(json_data); + free(params_data); dlclose(bundle); return 0;