2121#include < assert.h>
2222#include < dlpack/dlpack.h>
2323#include < dmlc/json.h>
24+ #include < tvm/runtime/ndarray.h>
25+ #include < tvm/runtime/packed_func.h>
2426
2527#include < limits>
2628#include < string>
2729#include < unordered_map>
2830#include < utility>
2931#include < vector>
32+ namespace tvm {
33+ namespace runtime {
3034/* !
3135 * \brief All binding information of a output interface.
3236 */
@@ -292,7 +296,106 @@ struct ParamConnectionConfig {
292296 }
293297 }
294298};
299+ /*
300+ *\brief Backend Runtime.
301+ */
302+ class BackendRuntime {
303+ private:
304+ /* \brief The index of runtime indicates the runtime position in the pipeline.*/
305+ int runtime_idx_;
306+ /* \brief The Runtime module of a backend graph executor.*/
307+ Module module_;
308+ /* !
309+ *\brief In order to transfer data from one backend runtime to another, we need a local
310+ * tensor variable as a medium. "input_tensor_local_copy_" is a map including
311+ * input data and local tensor vairable.
312+ */
313+ std::unordered_map<DLTensor*, DLTensor*> input_tensor_local_copy_;
314+ /* !\brief The packed functions.*/
315+ tvm::runtime::PackedFunc set_input_;
316+ tvm::runtime::PackedFunc get_input_;
317+ tvm::runtime::PackedFunc get_num_output_;
318+ tvm::runtime::PackedFunc get_num_inputs_;
319+ tvm::runtime::PackedFunc get_input_index_;
320+ /* !
321+ * \brief Copying from a given tensor and using 'CPU' as the device.
322+ */
323+ inline DLTensor* CopyDLTensorToCPU (const DLTensor* from) {
324+ DLTensor* ret = NULL ;
325+ TVMArrayAlloc (from->shape , from->ndim , from->dtype .code , from->dtype .bits , from->dtype .lanes ,
326+ kDLCPU , 0 , &ret);
327+ return ret;
328+ }
329+ /* !\brief Creating a new NDArray with same shape and data type as the given DLTensor.*/
330+ NDArray CreateNDArrayFromDLTensor (const DLTensor* from) {
331+ std::vector<int64_t > shape;
332+ for (int i = 0 ; i < from->ndim ; i++) {
333+ shape.push_back (from->shape [i]);
334+ }
335+ auto ndarray = NDArray::Empty (shape, from->dtype , from->device );
336+ ndarray.CreateView (shape, from->dtype );
337+ return ndarray;
338+ }
339+ /*
340+ *\brief Copying data from one DLTensor to another.
341+ */
342+ void CopyFromTo (DLTensor* from, DLTensor* to) {
343+ // When the 'from' device and the 'to' device are not the same, we use a temporary CPU
344+ // DLTensor as the bridge.
345+ if (from->device .device_type != to->device .device_type && from->device .device_type != kDLCPU &&
346+ to->device .device_type != kDLCPU ) {
347+ DLTensor* dltensor_local = nullptr ;
348+ if (input_tensor_local_copy_.find (to) == input_tensor_local_copy_.end ()) {
349+ dltensor_local = CopyDLTensorToCPU (from);
350+ input_tensor_local_copy_[to] = dltensor_local;
351+ } else {
352+ dltensor_local = input_tensor_local_copy_[to];
353+ }
354+ TVMArrayCopyFromTo (from, dltensor_local, nullptr );
355+ from = dltensor_local;
356+ }
295357
358+ TVMArrayCopyFromTo (from, to, nullptr );
359+ }
360+
361+ public:
362+ BackendRuntime (Module mod, int mod_idx) {
363+ module_ = mod;
364+ runtime_idx_ = mod_idx;
365+ get_input_index_ = module_.GetFunction (" get_input_index" );
366+ get_num_output_ = module_.GetFunction (" get_num_outputs" );
367+ get_num_inputs_ = module_.GetFunction (" get_num_inputs" );
368+ set_input_ = module_.GetFunction (" set_input" );
369+ get_input_ = module_.GetFunction (" get_input" );
370+ }
371+ BackendRuntime (void ) {}
372+ ~BackendRuntime () {
373+ for (auto data : input_tensor_local_copy_) {
374+ TVMArrayFree (data.second );
375+ }
376+ }
377+ /* !\brief Return the index of the current module.*/
378+ int GetModuleIndex () { return runtime_idx_; }
379+ /* !\brief Return the number of output*/
380+ int NumOutputs () const { return get_num_output_ (); }
381+ /* !\brief Return the number of input*/
382+ int NumInputs () const { return get_num_inputs_ (); }
383+ /* !\brief Setting the data to this module via input index.*/
384+ void SetInput (const int index, DLTensor* data_in) {
385+ NDArray input = get_input_ (index);
386+ DLTensor* dltensor_input = const_cast <DLTensor*>(input.operator ->());
387+ CopyFromTo (data_in, dltensor_input);
388+ }
389+ /* !\brief Setting the data to the current runtime moduel via the input name. */
390+ void SetInput (const std::string name, DLTensor* data_in) {
391+ int index = this ->GetInputIndex (name);
392+ SetInput (index, data_in);
393+ }
394+ /* !\brief Getting the input data via the input index.*/
395+ NDArray GetInput (int index) const { return get_input_ (index); }
396+ /* !\bief Getting the input data via the input name.*/
397+ int GetInputIndex (const std::string& name) { return get_input_index_ (name); }
398+ };
296399/* !
297400 * \brief The information used to initialize the graph executor module, the information
298401 * come from the export library function call.
@@ -309,4 +412,6 @@ struct GraphModuleLoadInfo {
309412};
310413/* ! The Module information of each module.The 'int' is module index. */
311414using ModuleConfig = std::unordered_map<int , GraphModuleLoadInfo>;
415+ }; // namespace runtime
416+ }; // namespace tvm
312417#endif // TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_
0 commit comments