Add onnxifi interface for set/get options (#52388)

Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/52388

Pull Request resolved: https://github.com/pytorch/glow/pull/5364

This allows us to change global variables through onnxifi calls. And add python bindings along with it. Note that we supply a dummy backend_id as it's not needed by glow due to setting being global.

#codemod

Test Plan:
```
buck test mode/dev //glow/fb/test:test_onnxifi_optionnnpi
```

Reviewed By: jfix71, khabinov

Differential Revision: D26481652

fbshipit-source-id: 19b8201c77f653cf7d93ad68760aa7fb5ec45ff4
diff --git a/caffe2/opt/onnxifi_transformer.cc b/caffe2/opt/onnxifi_transformer.cc
index 79634bb..525f564 100644
--- a/caffe2/opt/onnxifi_transformer.cc
+++ b/caffe2/opt/onnxifi_transformer.cc
@@ -483,6 +483,71 @@
   new_net.Swap(net);
 }
 
+OnnxifiOptionHelper::OnnxifiOptionHelper() {
+  lib_ = onnx::initOnnxifiLibrary();
+  CAFFE_ENFORCE(lib_, "Cannot initialize ONNXIFI library");
+}
+
+bool OnnxifiOptionHelper::setOnnxifiOption(
+    const std::string& option,
+    const std::string& value) {
+#ifdef ONNXIFI_ENABLE_EXT
+  onnxStatus (*onnxSetOptionFunctionPointer)(
+      const char* optionName, const char* optionValue) = nullptr;
+  union {
+    onnxExtensionFunctionPointer p;
+    decltype(onnxSetOptionFunctionPointer) set;
+  } u{};
+  onnxBackendID backend_id = nullptr;
+  if (lib_->onnxGetExtensionFunctionAddress(
+          backend_id, "onnxSetOptionFunction", &u.p) !=
+      ONNXIFI_STATUS_SUCCESS) {
+    LOG(ERROR) << "Cannot find onnxSetOptionFunction";
+    return false;
+  } else {
+    onnxSetOptionFunctionPointer = u.set;
+  }
+  if (onnxSetOptionFunctionPointer != nullptr &&
+      (*onnxSetOptionFunctionPointer)(option.c_str(), value.c_str()) ==
+          ONNXIFI_STATUS_SUCCESS) {
+    return true;
+  }
+#endif
+  return false;
+}
+
+std::string OnnxifiOptionHelper::getOnnxifiOption(const std::string& option) {
+#ifdef ONNXIFI_ENABLE_EXT
+  onnxStatus (*onnxGetOptionFunctionPointer)(
+      const char* optionName, char* optionValue, size_t* optionValueLength) =
+      nullptr;
+  union {
+    onnxExtensionFunctionPointer p;
+    decltype(onnxGetOptionFunctionPointer) get;
+  } u{};
+  onnxBackendID backend_id = nullptr;
+  if (lib_->onnxGetExtensionFunctionAddress(
+          backend_id, "onnxGetOptionFunction", &u.p) !=
+      ONNXIFI_STATUS_SUCCESS) {
+    LOG(ERROR) << "Cannot find onnxGetOptionFunction";
+    return "";
+  } else {
+    onnxGetOptionFunctionPointer = u.get;
+  }
+
+  constexpr size_t ll = 1024;
+  char buf[ll];
+  size_t len = ll;
+  if (onnxGetOptionFunctionPointer != nullptr &&
+      (*onnxGetOptionFunctionPointer)(option.c_str(), buf, &len) ==
+          ONNXIFI_STATUS_SUCCESS) {
+    return std::string(buf, len);
+  }
+#endif
+
+  return "";
+}
+
 OnnxifiTransformer::OnnxifiTransformer(const OnnxifiTransformerOptions& opts)
     : BackendTransformerBase(), opts_(opts) {
   lib_ = onnx::initOnnxifiLibrary();
@@ -537,7 +602,7 @@
     const std::vector<std::string>& external_inputs,
     const std::vector<std::string>& external_outputs,
     const ShapeInfoMap& shape_hints_max_bs,
-    const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs) {
+    const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs) {
   OperatorDef op;
   op.set_type("Onnxifi");
   auto* onnx_model_arg = op.add_arg();
@@ -577,7 +642,10 @@
     if (!initialization_list.count(input)) {
       const auto it = shape_hints_max_bs.find(input);
       CAFFE_ENFORCE(
-          it != shape_hints_max_bs.end(), "Input shape for ", input, " not found");
+          it != shape_hints_max_bs.end(),
+          "Input shape for ",
+          input,
+          " not found");
       const auto& info = it->second;
       if (info.getDimType(0) == TensorBoundShape_DimType_BATCH &&
           getBlob1stDimSize(info) == max_batch_size) {
@@ -610,7 +678,8 @@
 
   // Add output size hints per batch size
   if (canPassOutputShapeHintsPerBs(op, shape_hints_per_bs)) {
-    VLOG(2) << "Passing in output shape hints for batch sizes in [1, " << opts_.bound_shape_spec.max_batch_size << ")";
+    VLOG(2) << "Passing in output shape hints for batch sizes in [1, "
+            << opts_.bound_shape_spec.max_batch_size << ")";
     AddArgument("use_passed_output_shapes", 1, &op);
 
     for (int bs = 1; bs < opts_.bound_shape_spec.max_batch_size; ++bs) {
@@ -625,9 +694,11 @@
         const auto& output_name = op.output(output_idx);
         const auto& shape_hint = shape_hints.find(output_name)->second;
         if (!shape_hint.is_quantized) {
-          output_shape_arg->mutable_tensors()->Add()->CopyFrom(wrapShapeInfoIntoTensorProto(output_name, shape_hint));
+          output_shape_arg->mutable_tensors()->Add()->CopyFrom(
+              wrapShapeInfoIntoTensorProto(output_name, shape_hint));
         } else {
-          output_shape_arg->mutable_qtensors()->Add()->CopyFrom(wrapShapeInfoIntoQTensorProto(output_name, shape_hint));
+          output_shape_arg->mutable_qtensors()->Add()->CopyFrom(
+              wrapShapeInfoIntoQTensorProto(output_name, shape_hint));
         }
       }
     }
@@ -663,7 +734,7 @@
     const caffe2::NetDef& net,
     const std::unordered_set<std::string>& weights_in_ws,
     const ShapeInfoMap& shape_hints_max_bs,
-    const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs) {
+    const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs) {
   int onnxifi_op_id = onnxifi_op_id_;
   if (opts_.debug) {
     WriteProtoToTextFile(
@@ -802,7 +873,7 @@
     Workspace* ws,
     onnx::OnnxExporter* exporter,
     ShapeInfoMap* shape_hints_max_bs,
-    const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs) {
+    const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs) {
   if (opts_.min_ops > net.op_size()) {
     return net;
   }
@@ -1222,22 +1293,24 @@
     const std::unordered_set<std::string>& weights,
     const std::unordered_set<int>& blocklisted_ops,
     const ShapeInfoMap& shape_hints_max_bs,
-    const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs) {
+    const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs) {
   onnxBackendID backend_id = backend_ids_[idx_];
 
-  auto c2_supports = [this,
-                      &shape_hints_max_bs,
-                      &blocklisted_ops,
-                      backend_id,
-                      &weights](const caffe2::OperatorDef& op) {
-    return supportOpC2(op, shape_hints_max_bs, weights, blocklisted_ops, backend_id);
-  };
-
-  auto c2_converter =
-      [this, &weights, &shape_hints_max_bs, &shape_hints_per_bs](const caffe2::NetDef& net) {
-        return SubnetToOnnxifiOpViaC2(net, weights, shape_hints_max_bs, shape_hints_per_bs);
+  auto c2_supports =
+      [this, &shape_hints_max_bs, &blocklisted_ops, backend_id, &weights](
+          const caffe2::OperatorDef& op) {
+        return supportOpC2(
+            op, shape_hints_max_bs, weights, blocklisted_ops, backend_id);
       };
 
+  auto c2_converter = [this,
+                       &weights,
+                       &shape_hints_max_bs,
+                       &shape_hints_per_bs](const caffe2::NetDef& net) {
+    return SubnetToOnnxifiOpViaC2(
+        net, weights, shape_hints_max_bs, shape_hints_per_bs);
+  };
+
   return opt::OptimizeForBackend(
       *pred_net, c2_supports, c2_converter, opts_.debug);
 }
@@ -1248,7 +1321,7 @@
     const std::unordered_set<std::string>& weights,
     const std::unordered_set<int>& blocklisted_ops,
     ShapeInfoMap* shape_hints_max_bs,
-    const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs) {
+    const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs) {
   onnxBackendID backend_id = backend_ids_[idx_];
 
   // function to tell whether the ONNXIFI backend supports a given C2 op or not
@@ -1262,9 +1335,15 @@
   // the same exporter throughout the process to avoid duplicated dummy name
   // generation
   onnx::OnnxExporter exporter2(nullptr);
-  auto onnx_converter = [this, ws, &weights, shape_hints_max_bs, &exporter2, &shape_hints_per_bs](
+  auto onnx_converter = [this,
+                         ws,
+                         &weights,
+                         shape_hints_max_bs,
+                         &exporter2,
+                         &shape_hints_per_bs](
                             const caffe2::NetDef& net) mutable {
-    return SubnetToOnnxifiOpViaOnnx(net, weights, ws, &exporter2, shape_hints_max_bs, shape_hints_per_bs);
+    return SubnetToOnnxifiOpViaOnnx(
+        net, weights, ws, &exporter2, shape_hints_max_bs, shape_hints_per_bs);
   };
 
   return opt::OptimizeForBackend(
@@ -1334,7 +1413,10 @@
   }
   if (opts_.merge_fp32_inputs_into_fp16) {
     mergeFp32InputsAndConvertToFp16(
-        opts_.bound_shape_spec.max_batch_size, weights, pred_net, &shape_hints_max_bs);
+        opts_.bound_shape_spec.max_batch_size,
+        weights,
+        pred_net,
+        &shape_hints_max_bs);
   }
 
   if (opts_.debug) {
@@ -1355,13 +1437,23 @@
   // Apply some filtering rules
   std::unordered_set<int> new_blocklisted_ops(
       blocklisted_ops.begin(), blocklisted_ops.end());
-  applyFilteringRules(*pred_net, shape_hints_max_bs, weights, &new_blocklisted_ops);
+  applyFilteringRules(
+      *pred_net, shape_hints_max_bs, weights, &new_blocklisted_ops);
 
   // Transform the net
-  NetDef net_opt = opts_.use_onnx
-      ? TransformViaOnnx(
-            ws, pred_net, weights, new_blocklisted_ops, &shape_hints_max_bs, opts_.shape_hints_per_bs)
-      : TransformViaC2(pred_net, weights, new_blocklisted_ops, shape_hints_max_bs, opts_.shape_hints_per_bs);
+  NetDef net_opt = opts_.use_onnx ? TransformViaOnnx(
+                                        ws,
+                                        pred_net,
+                                        weights,
+                                        new_blocklisted_ops,
+                                        &shape_hints_max_bs,
+                                        opts_.shape_hints_per_bs)
+                                  : TransformViaC2(
+                                        pred_net,
+                                        weights,
+                                        new_blocklisted_ops,
+                                        shape_hints_max_bs,
+                                        opts_.shape_hints_per_bs);
 
   // Need to figure out a proper place to handle device option
   net_opt.mutable_device_option()->CopyFrom(pred_net->device_option());
diff --git a/caffe2/opt/onnxifi_transformer.h b/caffe2/opt/onnxifi_transformer.h
index d1af173..56bd1cd 100644
--- a/caffe2/opt/onnxifi_transformer.h
+++ b/caffe2/opt/onnxifi_transformer.h
@@ -49,6 +49,21 @@
   std::unordered_map<int, ShapeInfoMap> shape_hints_per_bs;
 };
 
+class TORCH_API OnnxifiOptionHelper final {
+ public:
+  OnnxifiOptionHelper();
+
+  // Set Onnxifi option
+  bool setOnnxifiOption(const std::string& option, const std::string& value);
+
+  //  Get Onnxifi option
+  std::string getOnnxifiOption(const std::string& option);
+
+ private:
+  // Pointer to loaded onnxifi library
+  onnxifi_library* lib_{nullptr};
+};
+
 class TORCH_API OnnxifiTransformer final : public BackendTransformerBase {
  public:
   explicit OnnxifiTransformer(const OnnxifiTransformerOptions& opts);
@@ -84,14 +99,14 @@
       Workspace* ws,
       onnx::OnnxExporter* exporter,
       ShapeInfoMap* shape_hints_max_bs,
-      const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs);
+      const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs);
 
   // Convert a cutoff subgraph net to an Onnxifi op
   caffe2::NetDef SubnetToOnnxifiOpViaC2(
       const caffe2::NetDef& net,
       const std::unordered_set<std::string>& weights_in_ws,
       const ShapeInfoMap& shape_hints_max_bs,
-      const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs);
+      const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs);
 
   // Check that output shape hints are present to ensure we can pass them to
   // OnnxifiOp
@@ -106,7 +121,7 @@
       const std::vector<std::string>& external_inputs,
       const std::vector<std::string>& external_outputs,
       const ShapeInfoMap& shape_hints_max_bs,
-      const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs);
+      const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs);
 
   // Transform by passing C2 proto to backend
   NetDef TransformViaC2(
@@ -114,7 +129,7 @@
       const std::unordered_set<std::string>& weights,
       const std::unordered_set<int>& blocklisted_ops,
       const ShapeInfoMap& shape_hints_max_bs,
-      const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs);
+      const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs);
 
   // Transform by passing ONNX proto to backend
   NetDef TransformViaOnnx(
@@ -123,7 +138,7 @@
       const std::unordered_set<std::string>& weights,
       const std::unordered_set<int>& blocklisted_ops,
       ShapeInfoMap* shape_hints_max_bs,
-      const std::unordered_map<int, ShapeInfoMap> &shape_hints_per_bs);
+      const std::unordered_map<int, ShapeInfoMap>& shape_hints_per_bs);
 
   // Query whether an operator is supported by passing ONNX protobuf
   bool supportOpOnnx(
diff --git a/caffe2/python/onnx/onnxifi.py b/caffe2/python/onnx/onnxifi.py
index 3e67c49..973d063 100644
--- a/caffe2/python/onnx/onnxifi.py
+++ b/caffe2/python/onnx/onnxifi.py
@@ -5,15 +5,23 @@
 ONNXIFI a Caffe2 net
 """
 
-
-
-
-
-
 from caffe2.proto import caffe2_pb2
 import caffe2.python._import_c_extension as C
 
 
+def onnxifi_set_option(option_name, option_value):
+    """
+    Set onnxifi option
+    """
+    return C.onnxifi_set_option(option_name, str(option_value))
+
+
+def onnxifi_get_option(option_name):
+    """
+    Get onnxifi option
+    """
+    return C.onnxifi_get_option(option_name)
+
 def onnxifi_caffe2_net(
         pred_net,
         input_shapes,
diff --git a/caffe2/python/pybind_state.cc b/caffe2/python/pybind_state.cc
index 65a246e..87f95d9 100644
--- a/caffe2/python/pybind_state.cc
+++ b/caffe2/python/pybind_state.cc
@@ -23,13 +23,13 @@
 #include "caffe2/onnx/offline_tensor.h"
 #include "caffe2/onnx/onnx_exporter.h"
 #include "caffe2/opt/converter.h"
+#include "caffe2/opt/fakefp16_transform.h"
 #include "caffe2/opt/fusion.h"
 #include "caffe2/opt/mobile.h"
 #include "caffe2/opt/onnxifi_transformer.h"
 #include "caffe2/opt/optimize_ideep.h"
 #include "caffe2/opt/passes.h"
 #include "caffe2/opt/shape_info.h"
-#include "caffe2/opt/fakefp16_transform.h"
 #include "caffe2/predictor/emulator/data_filler.h"
 #include "caffe2/predictor/predictor.h"
 #include "caffe2/python/pybind_state_registry.h"
@@ -85,14 +85,13 @@
   return gWorkspace;
 }
 
-Workspace* GetWorkspaceByName(const std::string &name) {
+Workspace* GetWorkspaceByName(const std::string& name) {
   if (gWorkspaces.count(name)) {
     return gWorkspaces[name].get();
   }
   return nullptr;
 }
 
-
 class StringFetcher : public BlobFetcherBase {
  public:
   py::object Fetch(const Blob& blob) override {
@@ -376,10 +375,9 @@
             py::gil_scoped_release g;
             CAFFE_ENFORCE(net->Run());
           })
-      .def("cancel",
-          [](NetBase* net) {
-            py::gil_scoped_release g;
-            net->Cancel();
+      .def("cancel", [](NetBase* net) {
+        py::gil_scoped_release g;
+        net->Cancel();
       });
 
   py::class_<ObserverBase<NetBase>>(m, "Observer")
@@ -1763,6 +1761,17 @@
         return true;
       });
   m.def(
+      "onnxifi_set_option",
+      [](const std::string& optionName,
+         const std::string& optionValue) -> bool {
+        OnnxifiOptionHelper ts;
+        return ts.setOnnxifiOption(optionName, optionValue);
+      });
+  m.def("onnxifi_get_option", [](const std::string& optionName) -> std::string {
+    OnnxifiOptionHelper ts;
+    return ts.getOnnxifiOption(optionName);
+  });
+  m.def(
       "onnxifi",
       [](const py::bytes& pred_net_str,
          const py::bytes& shapes_str,
@@ -1840,8 +1849,7 @@
   m.def("fakeFp16FuseOps", [](const py::bytes& net_str) {
     caffe2::NetDef netDef;
     CAFFE_ENFORCE(
-        ParseProtoFromLargeString(
-            net_str.cast<std::string>(), &netDef),
+        ParseProtoFromLargeString(net_str.cast<std::string>(), &netDef),
         "broken pred_net protobuf");
     opt::fakeFp16FuseOps(&netDef);
     std::string out_net;
diff --git a/third_party/foxi b/third_party/foxi
index 6a4e19a..bd6feb6 160000
--- a/third_party/foxi
+++ b/third_party/foxi
@@ -1 +1 @@
-Subproject commit 6a4e19a2aaf7ae4b9fa9597526e65b395d5e79ad
+Subproject commit bd6feb6d0d3fc903df42b4feb82a602a5fcb1fd5