masahi commented on a change in pull request #9108: URL: https://github.com/apache/tvm/pull/9108#discussion_r727593939
########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. Review comment: What is "correct" index ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor Review comment: variable ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { + reader->Read(&binding); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + ICHECK(output_idx >= 0); + output_binding_map[output_idx] = binding; + } + } +}; +/*! + * \brief The binding or dependency information of each module output interface. + */ +struct PipelineConfig { + /*!\brief The module index is the key, this variable records all module pipeline configuration + * information. + */ + std::unordered_map<int, OutputMap> config; + OutputMap& operator[](int key) { + ICHECK(config.find(key) != config.end()); + return config[key]; + } + + void Insert(int key, const OutputMap& map) { config[key] = map; } + + /*!\brief This function is used to verify whether config is loaded successfully. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return config.empty(); } + + /*! + * \brief Get the number of global outputs that is the outputs of entire pipeline. + * \return How much output does the entire pipeline have. Review comment: * \brief Get the number of global outputs. * \return The number of output the entire pipeline has. ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { + reader->Read(&binding); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + ICHECK(output_idx >= 0); + output_binding_map[output_idx] = binding; + } + } +}; +/*! + * \brief The binding or dependency information of each module output interface. + */ +struct PipelineConfig { + /*!\brief The module index is the key, this variable records all module pipeline configuration + * information. + */ + std::unordered_map<int, OutputMap> config; + OutputMap& operator[](int key) { + ICHECK(config.find(key) != config.end()); + return config[key]; + } + + void Insert(int key, const OutputMap& map) { config[key] = map; } + + /*!\brief This function is used to verify whether config is loaded successfully. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return config.empty(); } + + /*! + * \brief Get the number of global outputs that is the outputs of entire pipeline. + * \return How much output does the entire pipeline have. Review comment: ``` * \brief Get the number of global outputs. * \return The number of output the entire pipeline has. ``` ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { + reader->Read(&binding); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + ICHECK(output_idx >= 0); + output_binding_map[output_idx] = binding; + } + } +}; +/*! + * \brief The binding or dependency information of each module output interface. + */ +struct PipelineConfig { + /*!\brief The module index is the key, this variable records all module pipeline configuration + * information. + */ + std::unordered_map<int, OutputMap> config; + OutputMap& operator[](int key) { + ICHECK(config.find(key) != config.end()); + return config[key]; + } + + void Insert(int key, const OutputMap& map) { config[key] = map; } + + /*!\brief This function is used to verify whether config is loaded successfully. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return config.empty(); } + + /*! + * \brief Get the number of global outputs that is the outputs of entire pipeline. + * \return How much output does the entire pipeline have. Review comment: ``` * \brief Get the number of global outputs. * \return The number of outputs the entire pipeline has. ``` ########## File path: python/tvm/contrib/pipeline_executor.py ########## @@ -72,22 +73,69 @@ def build(pipe_configs): mconf["dev"] = "{},{}".format(dev.device_type, dev.device_id) # Create a pipeline configuration. string_config[mod_idx] = mconf - mods[mod] = {"dev": dev} + libs[mod_idx] = {"lib": lib, "dev": dev} - return PipelineExecutorFactoryModule(mods, string_config) + return PipelineExecutorFactoryModule(libs, string_config) class PipelineModule(object): """Wrapper of runtime module, caller can use this module to set parameters and get outputs. Parameters ---------- - module : PipelineExecutorFactoryModule - Common interface for pipeline executor factory modules. + module : Union[PipelineExecutorFactoryModule, Module] + Common interface for pipeline executor factory modules or Module. """ def __init__(self, module): - self.module = module.module + if isinstance(module, PipelineExecutorFactoryModule): + self.module = module.module + else: + self.module = module + # Get the packed functions from the pipeline executor. + self._get_num_outputs = self.module["get_num_outputs"] + + @property + def num_outputs(self): + """Get the number of outputs. + Returns + ------- + count : int + The number of outputs. + """ + return self._get_num_outputs() + + @staticmethod + def load_library(config_file_name): + """Import files to create a pipeline executor. + + Parameters + ---------- + config_file_name : str + Path and name of the configuration file, the configuration file contains the + disk path of the parameter file, library file, and JSON file. + """ + with open(config_file_name, "r") as file_handle: + config = file_handle.read() + config = json.loads(config) + if "load_config" not in config or "pipeline_config" not in config: + raise RuntimeError( + '"load_config" or "pipeline_config" is missing in %s' % config_file_name + ) + + # The config file use to load library, prameters, and JSON files. Review comment: used ########## File path: python/tvm/contrib/pipeline_executor.py ########## @@ -72,22 +73,69 @@ def build(pipe_configs): mconf["dev"] = "{},{}".format(dev.device_type, dev.device_id) # Create a pipeline configuration. string_config[mod_idx] = mconf - mods[mod] = {"dev": dev} + libs[mod_idx] = {"lib": lib, "dev": dev} - return PipelineExecutorFactoryModule(mods, string_config) + return PipelineExecutorFactoryModule(libs, string_config) class PipelineModule(object): """Wrapper of runtime module, caller can use this module to set parameters and get outputs. Parameters ---------- - module : PipelineExecutorFactoryModule - Common interface for pipeline executor factory modules. + module : Union[PipelineExecutorFactoryModule, Module] + Common interface for pipeline executor factory modules or Module. """ def __init__(self, module): - self.module = module.module + if isinstance(module, PipelineExecutorFactoryModule): + self.module = module.module + else: + self.module = module + # Get the packed functions from the pipeline executor. + self._get_num_outputs = self.module["get_num_outputs"] + + @property + def num_outputs(self): + """Get the number of outputs. + Returns + ------- + count : int + The number of outputs. + """ + return self._get_num_outputs() + + @staticmethod + def load_library(config_file_name): + """Import files to create a pipeline executor. + + Parameters + ---------- + config_file_name : str + Path and name of the configuration file, the configuration file contains the + disk path of the parameter file, library file, and JSON file. + """ + with open(config_file_name, "r") as file_handle: + config = file_handle.read() + config = json.loads(config) + if "load_config" not in config or "pipeline_config" not in config: + raise RuntimeError( + '"load_config" or "pipeline_config" is missing in %s' % config_file_name + ) + + # The config file use to load library, prameters, and JSON files. + with open(config["load_config"], "r") as file_handle: + load_config = file_handle.read() + + # The config file use to load pipeline compute config. Review comment: used ########## File path: python/tvm/contrib/pipeline_executor.py ########## @@ -139,13 +187,14 @@ def get_owner_idx(self): if isinstance(self.io_owner, PipelineConfig.ModuleWrapper): return self.io_owner.idx - return 0 + return -1 - def is_global_interface(self): - """The global interface is the interface visible to the caller which use a pipeline - executor, the global input interface is responsible for passing parameters to the - internal module interface, and the global output interface is responsible for - outputting the results computed by the pipeline executor to a caller. + def is_pipeline_executor_interface(self): + """The pipeline interface is used to interact with the caller, there are two types + such interfaces, one is 'input' another is 'output'. the pipeline input interface + is responsible for passing parameters to the internal module interface, and the + pipeline output interface is responsible for outputting the results computed by + the pipeline executor to a caller. Review comment: ``` The pipeline interface is used to interact with the caller. There are two types of interfaces, one is 'input' and another is 'output'. The pipeline input interface is responsible for passing parameters to the internal module interface, and the pipeline output interface is responsible for outputting the results computed by the pipeline executor to the caller. ``` ########## File path: python/tvm/contrib/pipeline_executor.py ########## @@ -139,13 +187,14 @@ def get_owner_idx(self): if isinstance(self.io_owner, PipelineConfig.ModuleWrapper): return self.io_owner.idx - return 0 + return -1 - def is_global_interface(self): - """The global interface is the interface visible to the caller which use a pipeline - executor, the global input interface is responsible for passing parameters to the - internal module interface, and the global output interface is responsible for - outputting the results computed by the pipeline executor to a caller. + def is_pipeline_executor_interface(self): + """The pipeline interface is used to interact with the caller, there are two types + such interfaces, one is 'input' another is 'output'. the pipeline input interface + is responsible for passing parameters to the internal module interface, and the + pipeline output interface is responsible for outputting the results computed by + the pipeline executor to a caller. Review comment: ``` The pipeline interface is used to interact with the caller. There are two types of interfaces, one is 'input' and another is 'output'. The pipeline input interface is responsible for passing parameters to the internal module interface, and the pipeline output interface is responsible for outputting the results computed by the pipeline executor to the caller. ``` ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. Review comment: a list of graph executor ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor Review comment: variable modules ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. Review comment: I suggest just remove this comment, becuase "All modules here are graph executor modules, hence the value of 'mod_idx' should start from 0" doesn't make much sense. ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. + ICHECK(mod_idx >= 0) << "Invalid mod_idx value " << mod_idx; + // Load the lib, json, and params information. + ICHECK(!lib_name.empty()) << "lib_name is empty."; + ICHECK(!json_name.empty()) << "json_name is empty."; + ICHECK(!params_name.empty()) << "params_name is empty."; + mod_config_[mod_idx] = GraphModuleLoadInfo(lib_name, json_name, params_name, dev); + } + return mod_config_; + } + + private: + /*!\brief The class used to execute and schedule the pipeline logic.*/ + PipelineScheduler pipeline_scheduler_; + /*!\brief The Dependency information of each graph runtime module of the pipeline.*/ + PipelineConfig pipeline_config_; + /*!\brief The Module information used to create the graph runtimes.*/ + ModuleConfig mod_config_; + /*!\brief How many outputs are in this pipeline executor.*/ + size_t num_outputs_ = 0; + /*!\brief Json loader.*/ + PipelineConfig& LoadPipelineConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + OutputMap output; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "dev") { + reader->Read(&dev); + } else if (key == "output") { + reader->Read(&output); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the variable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. Review comment: Remove this comment ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. + ICHECK(mod_idx >= 0) << "Invalid mod_idx value " << mod_idx; + // Load the lib, json, and params information. + ICHECK(!lib_name.empty()) << "lib_name is empty."; + ICHECK(!json_name.empty()) << "json_name is empty."; + ICHECK(!params_name.empty()) << "params_name is empty."; + mod_config_[mod_idx] = GraphModuleLoadInfo(lib_name, json_name, params_name, dev); + } + return mod_config_; + } + + private: + /*!\brief The class used to execute and schedule the pipeline logic.*/ + PipelineScheduler pipeline_scheduler_; + /*!\brief The Dependency information of each graph runtime module of the pipeline.*/ + PipelineConfig pipeline_config_; + /*!\brief The Module information used to create the graph runtimes.*/ + ModuleConfig mod_config_; + /*!\brief How many outputs are in this pipeline executor.*/ + size_t num_outputs_ = 0; + /*!\brief Json loader.*/ + PipelineConfig& LoadPipelineConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + OutputMap output; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "dev") { + reader->Read(&dev); + } else if (key == "output") { + reader->Read(&output); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the variable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. Review comment: Remove this comment for the same reason as https://github.com/apache/tvm/pull/9108/files#r727604211 ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { + reader->Read(&binding); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + ICHECK(output_idx >= 0); + output_binding_map[output_idx] = binding; + } + } +}; +/*! + * \brief The binding or dependency information of each module output interface. + */ +struct PipelineConfig { + /*!\brief The module index is the key, this variable records all module pipeline configuration Review comment: The key is the module index ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { + reader->Read(&binding); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + ICHECK(output_idx >= 0); + output_binding_map[output_idx] = binding; + } + } +}; +/*! + * \brief The binding or dependency information of each module output interface. + */ +struct PipelineConfig { + /*!\brief The module index is the key, this variable records all module pipeline configuration + * information. + */ + std::unordered_map<int, OutputMap> config; + OutputMap& operator[](int key) { + ICHECK(config.find(key) != config.end()); + return config[key]; + } + + void Insert(int key, const OutputMap& map) { config[key] = map; } + + /*!\brief This function is used to verify whether config is loaded successfully. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return config.empty(); } + + /*! + * \brief Get the number of global outputs that is the outputs of entire pipeline. + * \return How much output does the entire pipeline have. + */ + size_t GetGlobalOutputNum() const { + size_t num_output = 0; + for (auto mod_output : config) { + num_output += mod_output.second.GetGlobalOutputNum(); + } + return num_output; + } +}; +/*! + * \brief The informations used to initialize the graph executor module, the information Review comment: information ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. + ICHECK(mod_idx >= 0) << "Invalid mod_idx value " << mod_idx; + // Load the lib, json, and params information. + ICHECK(!lib_name.empty()) << "lib_name is empty."; + ICHECK(!json_name.empty()) << "json_name is empty."; + ICHECK(!params_name.empty()) << "params_name is empty."; + mod_config_[mod_idx] = GraphModuleLoadInfo(lib_name, json_name, params_name, dev); + } + return mod_config_; + } + + private: + /*!\brief The class used to execute and schedule the pipeline logic.*/ + PipelineScheduler pipeline_scheduler_; + /*!\brief The Dependency information of each graph runtime module of the pipeline.*/ Review comment: dependency ########## File path: src/runtime/pipeline/pipeline_executor.h ########## @@ -36,25 +43,114 @@ namespace runtime { * * This executor can be accessed by various language via TVM runtime PackedFunc API. */ -class TVM_DLL PipelineRuntime : public ModuleNode { +class TVM_DLL PipelineExecutor : public ModuleNode { public: /*! * \Return the type key of the executor. */ - const char* type_key() const final { return "PipelineRuntime"; } + const char* type_key() const final { return "PipelineExecutor"; } /*! - * \brief Initialize the pipeline executor with module array and json text. + * \brief Initialize the pipeline executor with module array and JSON text. * \param modules The module list used for building pipeline. * \param pipeline_json The configuration of modules dependencies. */ - void Init(const Array<tvm::runtime::Module>& modules, const std::string& pipeline_json); + void Init(const std::vector<Module>& modules, const std::string& pipeline_json); + /*! + * \brief Use the information of mod_config to create a graph executor list. + * \param mod_config The configuration information generated by the library export function call. + */ + std::vector<Module> CreateGraphModules(const ModuleConfig& mod_config); /*! * \brief Give frontends an access to packed functions. * \param name The name of the function. * \param sptr_to_self The pointer to the module node. * \return The corresponding packed function. */ virtual PackedFunc GetFunction(const std::string& name, const ObjectPtr<Object>& sptr_to_self); + + /*! + * \brief Get the number of outputs. + * + * \return The number of outputs. + */ + int NumOutputs() const { return num_outputs_; } + + /*!\brief Load the module files information.*/ + ModuleConfig& LoadModuleConfig(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int mod_idx = -1; + std::string lib_name; + std::string json_name; + std::string params_name; + std::string dev; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "lib_name") { + reader->Read(&lib_name); + } else if (key == "json_name") { + reader->Read(&json_name); + } else if (key == "params_name") { + reader->Read(¶ms_name); + } else if (key == "dev") { + reader->Read(&dev); + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // Check if the vairable 'mod_idx' is successfully read, All moudles here are graph executor + // modules, hence the value of 'mod_idx' should start from 0. + ICHECK(mod_idx >= 0) << "Invalid mod_idx value " << mod_idx; + // Load the lib, json, and params information. + ICHECK(!lib_name.empty()) << "lib_name is empty."; + ICHECK(!json_name.empty()) << "json_name is empty."; + ICHECK(!params_name.empty()) << "params_name is empty."; + mod_config_[mod_idx] = GraphModuleLoadInfo(lib_name, json_name, params_name, dev); + } + return mod_config_; + } + + private: + /*!\brief The class used to execute and schedule the pipeline logic.*/ + PipelineScheduler pipeline_scheduler_; + /*!\brief The Dependency information of each graph runtime module of the pipeline.*/ + PipelineConfig pipeline_config_; + /*!\brief The Module information used to create the graph runtimes.*/ Review comment: module ########## File path: src/runtime/pipeline/pipeline_struct.h ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ +#ifndef TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#define TVM_RUNTIME_PIPELINE_PIPELINE_STRUCT_H_ +#include <assert.h> +#include <dlpack/dlpack.h> +#include <dmlc/json.h> + +#include <limits> +#include <string> +#include <unordered_map> +#include <vector> +/*! + * \brief All binding information of a output interface. + */ +struct OutputBindings { + /*!\brief Output interface binding information, 'int' is the index of the module that + * uses this output data as the input interface data, 'string' is the input interface name + * of the module. + */ + std::unordered_map<int, std::string> bindings; + /*! The index value of the global interface to which the current output are bound.*/ + int global_output_index = std::numeric_limits<int>::min(); + /*!\brief Whether this binding is bound to the PipelineExecutor output interface.*/ + bool IsGlobalOutput() const { return global_output_index >= 0; } + /*! + * \brief Create a module interface map from JSONReader. + * \param reader JSON reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + std::string input_name; + int mod_idx = std::numeric_limits<int>::min(); + // Whether the output binding is global. + bool global_binding = false; + while (reader->NextObjectItem(&key)) { + if (key == "mod_idx") { + reader->Read(&mod_idx); + } else if (key == "input_name") { + reader->Read(&input_name); + } else if (key == "global_output_index") { + // There should be only one global binding. + ICHECK(global_output_index < 0); + reader->Read(&global_output_index); + // When the key value is 'global_output_index', it means that this output is bound to + // a global interface. + global_binding = true; + } else { + LOG(FATAL) << "do not support key " << key; + } + } + // When this output is bound to a global interface, check if the global interface index + // is correct. + if (global_binding) { + ICHECK(global_output_index >= 0); + } else { + // When this output is bound to a graph executor module interface, check if the module + // index is correct. + ICHECK(mod_idx >= 0); + bindings[mod_idx] = input_name; + } + } + } +}; + +/*! + * \brief The binding information of all outputs of a module. + */ +struct OutputMap { + /*! \brief Output binding map, 'int' is output interface index.*/ + std::unordered_map<int, OutputBindings> output_binding_map; + OutputMap& operator=(const OutputMap& output) { + output_binding_map = output.output_binding_map; + return *this; + } + + /*!\brief This function is used to verify whether OutputMap is successfully loaded. + * \return Return true to indicate that this class has not been successfully loaded. + */ + bool Empty() { return output_binding_map.empty(); } + /*! \brief The pipeline outputs is the final outputs of pipeline, this function is used to + * get how many pipeline outputs are in this Outputmap + * \return Number of pipeline outputs. + */ + size_t GetGlobalOutputNum(void) const { + size_t num_output = 0; + for (auto bindings : output_binding_map) { + num_output += bindings.second.IsGlobalOutput() ? 1 : 0; + } + return num_output; + } + + /*! + * \brief Create a output binding map from JSONReader. + * \param reader Json reader. + */ + void Load(dmlc::JSONReader* reader) { + reader->BeginArray(); + while (reader->NextArrayItem()) { + std::string key; + reader->BeginObject(); + int output_idx = -1; + OutputBindings binding; + while (reader->NextObjectItem(&key)) { + if (key == "output_idx") { + reader->Read(&output_idx); + } else if (key == "dependent") { Review comment: `dependent` -> `dependencies` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
