This is an automated email from the ASF dual-hosted git repository.

csullivan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new bafa3e9c22 [Hexagon] Add AoT capability to Hexagon launcher (#11214)
bafa3e9c22 is described below

commit bafa3e9c2247eabea1aaa3864dbde1334415d8b8
Author: Krzysztof Parzyszek <[email protected]>
AuthorDate: Wed May 4 18:09:00 2022 -0500

    [Hexagon] Add AoT capability to Hexagon launcher (#11214)
    
    * [Hexagon] Add AoT capability to Hexagon launcher
---
 apps/hexagon_launcher/README.md           | 19 ++++++++++++++++
 apps/hexagon_launcher/launcher_core.cc    | 37 +++++++++++++++++++++++++++++--
 apps/hexagon_launcher/launcher_core.h     |  4 ++--
 apps/hexagon_launcher/launcher_hexagon.cc | 27 +++++++++++++++++-----
 apps/hexagon_launcher/launcher_main.cc    |  9 ++++++--
 5 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/apps/hexagon_launcher/README.md b/apps/hexagon_launcher/README.md
index 5fc27cb253..210759a80c 100644
--- a/apps/hexagon_launcher/README.md
+++ b/apps/hexagon_launcher/README.md
@@ -170,6 +170,25 @@ A sample output JSON from running the Inception V3 model 
may look like
 }
 ```
 
+When using AoT, the `target` needs to be `llvm`:
+```
+aot_target = "llvm -keys=hexagon -link-params=0 
-mattr=+hvxv69,+hvx-length128b,+hvx-qfloat,-hvx-ieee-fp -mcpu=hexagonv69 
-mtriple=hexagon"
+aot_host_target = aot_target
+```
+
+Build the relay module specifying AoT as executor and CPP as runtime, and save 
it via `export_library`:
+```
+lowered = tvm.relay.build(
+    relay_mod,
+    params=params,
+    target=tvm.target.Target(aot_target, host=aot_host_target),
+    runtime=Runtime("cpp"),
+    executor=Executor("aot", {"unpacked-api": False, "interface-api": 
"packed"}),
+)
+
+lowered.export_library("model-aot.so", tvm.contrib.hexagon.link_shared)
+```
+
 # Disclaimer
 
 The launcher does not perform any correctness verification. In order to verify
diff --git a/apps/hexagon_launcher/launcher_core.cc 
b/apps/hexagon_launcher/launcher_core.cc
index 842406d950..a3993451c2 100644
--- a/apps/hexagon_launcher/launcher_core.cc
+++ b/apps/hexagon_launcher/launcher_core.cc
@@ -26,6 +26,8 @@
 #include <fstream>
 #include <ios>
 #include <iterator>
+#include <ostream>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -130,9 +132,9 @@ bool write_output_config(const std::string& file_name, 
OutputConfig* output_conf
 }
 
 Model::Model(tvm::runtime::Module executor, tvm::runtime::Module module, 
std::string json)
-    : graph_executor(executor), graph_module(module), graph_json(json) {
+    : model_executor(executor), graph_module(module), graph_json(json) {
   // Lookup "run" ahead of time to reduce overhead in the model execution.
-  run = get_module_func(graph_executor, "run");
+  run = get_module_func(model_executor, "run");
 }
 
 const tvm::runtime::PackedFunc get_runtime_func(const std::string& name) {
@@ -157,11 +159,23 @@ tvm::runtime::Module load_module(const std::string& 
file_name) {
       get_runtime_func("runtime.module.loadfile_hexagon");
   tvm::runtime::TVMRetValue rv = loader(file_name);
   if (rv.type_code() == kTVMModuleHandle) {
+    ICHECK_EQ(rv.type_code(), kTVMModuleHandle)
+        << __func__ << ": loaded " << file_name << ", but did not get module 
handle";
     return rv.operator tvm::runtime::Module();
   }
   return tvm::runtime::Module();
 }
 
+std::ostream& operator<<(std::ostream& os, const tvm::Array<tvm::String>& 
strings) {
+  os << '[';
+  for (int i = 0, e = strings.size(); i != e; ++i) {
+    if (i != 0) os << ',';
+    os << static_cast<std::string>(strings[i]);
+  }
+  os << ']';
+  return os;
+}
+
 tvm::runtime::Module create_graph_executor(const std::string& graph_json,
                                            tvm::runtime::Module graph_module, 
tvm::Device device) {
   std::string launcher_name = "tvm.graph_executor.create";
@@ -170,6 +184,25 @@ tvm::runtime::Module create_graph_executor(const 
std::string& graph_json,
   uint64_t device_type = device.device_type;
   uint64_t device_id = device.device_id;
 
+  if (graph_json.empty()) {
+    LOG(ERROR) << __func__ << ": graph executor requires graph JSON";
+    return tvm::runtime::Module();
+  }
   tvm::runtime::TVMRetValue rv = create_executor(graph_json, graph_module, 
device_type, device_id);
   return rv.operator tvm::runtime::Module();
 }
+
+tvm::runtime::Module create_aot_executor(tvm::runtime::Module factory_module, 
tvm::Device device) {
+  tvm::runtime::PackedFunc list_modules = get_module_func(factory_module, 
"list_module_names");
+  tvm::Array<tvm::String> module_names = list_modules();
+  if (module_names.size() != 1) {
+    LOG(WARNING) << __func__ << ": expecting single module, got: " << 
module_names << ", using "
+                 << module_names[0];
+  }
+  tvm::runtime::PackedFunc f = get_module_func(factory_module, 
module_names[0]);
+  if (f.get() == nullptr) {
+    LOG(ERROR) << __func__ << ": failed to obtain function " << 
module_names[0];
+    return tvm::runtime::Module();
+  }
+  return f(device);
+}
diff --git a/apps/hexagon_launcher/launcher_core.h 
b/apps/hexagon_launcher/launcher_core.h
index 91384133ab..a32bf937af 100644
--- a/apps/hexagon_launcher/launcher_core.h
+++ b/apps/hexagon_launcher/launcher_core.h
@@ -83,12 +83,11 @@ struct OutputConfig {
 struct Model {
   Model(tvm::runtime::Module executor, tvm::runtime::Module module, 
std::string json);
 
-  tvm::runtime::Module graph_executor;
+  tvm::runtime::Module model_executor;
   tvm::runtime::Module graph_module;
   std::string graph_json;
 
   static tvm::Device device() { return 
tvm::Device{static_cast<DLDeviceType>(kDLHexagon), 0}; }
-
   static tvm::Device external() { return 
tvm::Device{static_cast<DLDeviceType>(kDLCPU), 0}; }
 
   tvm::runtime::PackedFunc run;
@@ -125,6 +124,7 @@ const tvm::runtime::PackedFunc get_runtime_func(const 
std::string& name);
 const tvm::runtime::PackedFunc get_module_func(tvm::runtime::Module module,
                                                const std::string& name);
 
+tvm::runtime::Module create_aot_executor(tvm::runtime::Module factory_module, 
tvm::Device device);
 tvm::runtime::Module create_graph_executor(const std::string& graph_json,
                                            tvm::runtime::Module graph_module, 
tvm::Device device);
 
diff --git a/apps/hexagon_launcher/launcher_hexagon.cc 
b/apps/hexagon_launcher/launcher_hexagon.cc
index 4159391b26..d4fbf4bf5d 100644
--- a/apps/hexagon_launcher/launcher_hexagon.cc
+++ b/apps/hexagon_launcher/launcher_hexagon.cc
@@ -64,7 +64,22 @@ AEEResult __QAIC_HEADER(launcher_rpc_load)(remote_handle64 
handle, const char* m
   }
 
   tvm::runtime::Module module = load_module(module_path);
-  tvm::runtime::Module executor = create_graph_executor(graph_json, module, 
Model::device());
+  std::string module_type = module->type_key();
+  tvm::runtime::Module executor;
+  if (module_type == "AotExecutorFactory") {
+    executor = create_aot_executor(module, Model::external());
+  } else if (module_type == "library") {
+    // We're not expecting "GraphExecutorFactory" here.
+    executor = create_graph_executor(graph_json, module, Model::device());
+  } else {
+    LOG(ERROR) << __func__ << ": unexpected module type: " << module_type;
+    // Fall through.
+  }
+
+  if (executor.get() == nullptr) {
+    LOG(ERROR) << __func__ << ": failed to create executor for module" << 
module_path;
+    return AEE_EUNABLETOLOAD;
+  }
 
   TheModel = std::make_unique<Model>(executor, module, graph_json);
   return AEE_SUCCESS;
@@ -84,7 +99,7 @@ AEEResult 
__QAIC_HEADER(launcher_rpc_get_num_inputs)(remote_handle64 handle, int
   }
 
   tvm::runtime::PackedFunc get_num_inputs =
-      get_module_func(TheModel->graph_executor, "get_num_inputs");
+      get_module_func(TheModel->model_executor, "get_num_inputs");
   *num_inputs = get_num_inputs();
   return AEE_SUCCESS;
 }
@@ -119,7 +134,7 @@ AEEResult 
__QAIC_HEADER(launcher_rpc_set_input)(remote_handle64 handle, int inpu
 
   auto input = tvm::runtime::NDArray::FromDLPack(&managed);
 
-  tvm::runtime::PackedFunc set_input = 
get_module_func(TheModel->graph_executor, "set_input");
+  tvm::runtime::PackedFunc set_input = 
get_module_func(TheModel->model_executor, "set_input");
   set_input(input_idx, input);
 
   return AEE_SUCCESS;
@@ -132,7 +147,7 @@ AEEResult 
__QAIC_HEADER(launcher_rpc_get_num_outputs)(remote_handle64 handle, in
   }
 
   tvm::runtime::PackedFunc get_num_outputs =
-      get_module_func(TheModel->graph_executor, "get_num_outputs");
+      get_module_func(TheModel->model_executor, "get_num_outputs");
   *num_outputs = get_num_outputs();
   return AEE_SUCCESS;
 }
@@ -152,7 +167,7 @@ AEEResult 
__QAIC_HEADER(launcher_rpc_get_output)(remote_handle64 handle, int out
     return AEE_EBADPARM;
   }
 
-  tvm::runtime::PackedFunc get_output = 
get_module_func(TheModel->graph_executor, "get_output");
+  tvm::runtime::PackedFunc get_output = 
get_module_func(TheModel->model_executor, "get_output");
   tvm::runtime::NDArray output = get_output(output_idx);
 
   std::vector<int64_t> shape_vec{output->shape, output->shape + output->ndim};
@@ -163,7 +178,7 @@ AEEResult 
__QAIC_HEADER(launcher_rpc_get_output)(remote_handle64 handle, int out
     delete static_cast<tvm::runtime::NDArray::Container*>(container);
   });
 
-  tvm::runtime::NDArray host_output(GetObjectPtr<tvm::Object>(container));
+  tvm::runtime::NDArray 
host_output(tvm::runtime::GetObjectPtr<tvm::runtime::Object>(container));
 
   if (meta_size != 0) {
     auto* meta = reinterpret_cast<tensor_meta*>(output_meta);
diff --git a/apps/hexagon_launcher/launcher_main.cc 
b/apps/hexagon_launcher/launcher_main.cc
index ac21a7be16..163d582db4 100644
--- a/apps/hexagon_launcher/launcher_main.cc
+++ b/apps/hexagon_launcher/launcher_main.cc
@@ -76,8 +76,13 @@ int main(int argc, char* argv[]) {
   }
   ExecutionSession& session = *session_ptr;
 
-  std::cout << "loading model files: " << config.model_json << ", " << 
config.model_library << '\n';
-  std::string json = load_text_file(config.model_json);
+  std::cout << "loading model files: ";
+  if (!config.model_json.empty()) {
+    std::cout << config.model_json << ", ";
+  }
+  std::cout << config.model_library << '\n';
+
+  std::string json = !config.model_json.empty() ? 
load_text_file(config.model_json) : "";
   if (!session.load_model(config.model_library, json.c_str())) {
     return 1;
   }

Reply via email to