[ML][single] SingleShot.invoke implementation added 87/254287/4
authorRafal Walczyna <r.walczyna@samsung.com>
Thu, 25 Feb 2021 12:38:46 +0000 (13:38 +0100)
committerRafal Walczyna <r.walczyna@samsung.com>
Tue, 2 Mar 2021 10:56:15 +0000 (11:56 +0100)
ACR: TWDAPI-273

Test code:
var ti1 = new tizen.ml.TensorsInfo()
ti1.addTensorInfo("three", "FLOAT32", [1, 1, 1, 1])
var td1 = ti1.getTensorsData(0);
td1.setTensorRawData(0, [1]);
var ti3 = new tizen.ml.TensorsInfo()
ti3.addTensorInfo("three", "FLOAT32", [3, 1, 1, 1])
var td3 = ti3.getTensorsData(0);
td3.setTensorRawData(0, [1, 2, 3]);
var ti5 = new tizen.ml.TensorsInfo()
ti5.addTensorInfo("three", "FLOAT32", [5, 1, 1, 1])
var td5 = ti5.getTensorsData(0);
td5.setTensorRawData(0, [1, 2, 3, 4, 5]);

// using model from nnstreamer API
var m = tizen.ml.single.openModel('documents/add.tflite', null, null, "ANY", "ANY")

m.invoke(td1) // ok
m.invoke(td3) // error
m.invoke(td5) // error

var m_dynamic = tizen.ml.single.openModel('documents/add.tflite', null, null, "ANY", "ANY", true)

m_dynamic.invoke(td1) // ok
m_dynamic.invoke(td3) // ok
m_dynamic.invoke(td5) // ok

[Verification] Built successful. Tested in Chrome Dev console.

Change-Id: I25218c122c57d6cb781181388f94a27ee0605ee8
Signed-off-by: Rafal Walczyna <r.walczyna@samsung.com>
src/ml/js/ml_single.js
src/ml/ml_instance.cc
src/ml/ml_instance.h
src/ml/ml_single_manager.cc
src/ml/ml_single_manager.h
src/ml/ml_singleshot.cc
src/ml/ml_singleshot.h
src/ml/ml_tensors_data_manager.cc
src/ml/ml_tensors_data_manager.h
src/ml/ml_tensors_info_manager.cc
src/ml/ml_tensors_info_manager.h

index d516997..57fae3e 100755 (executable)
@@ -270,7 +270,39 @@ var SingleShot = function(id) {
     });
 };
 
-// SingleShot::invoke()
+var ValidInvokeExceptions = [
+    'TimeoutError',
+    'TypeMismatchError',
+    'NotSupportedError',
+    'AbortError'
+];
+
+SingleShot.prototype.invoke = function() {
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'inTensorsData',
+            type: types_.PLATFORM_OBJECT,
+            values: TensorsData
+        }
+    ]);
+
+    var nativeArgs = {
+        id: this._id,
+        tensorsDataId: args.inTensorsData._id
+    };
+
+    var result = native_.callSync('MLSingleShotInvoke', nativeArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            ValidInvokeExceptions,
+            AbortError
+        );
+    }
+
+    return new TensorsData(result.tensorsDataId, result.tensorsInfoId);
+};
 
 var GetSetValueValidExceptions = [
     'AbortError',
index 9eb99b6..1e188e1 100644 (file)
@@ -125,7 +125,7 @@ MlInstance::MlInstance()
   REGISTER_METHOD(MLSingleManagerOpenModel);
   REGISTER_METHOD(MLSingleShotGetTensorsInfo);
   REGISTER_METHOD(MLSingleShotSetInputInfo);
-  // SingleShot::invoke()
+  REGISTER_METHOD(MLSingleShotInvoke);
   REGISTER_METHOD(MLSingleShotGetValue);
   REGISTER_METHOD(MLSingleShotSetValue);
   // SingleShot::setTimeout()
@@ -888,7 +888,32 @@ void MlInstance::MLSingleShotSetInputInfo(const picojson::value& args, picojson:
   ReportSuccess(out);
 }
 
-// SingleShot::invoke()
+void MlInstance::MLSingleShotInvoke(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kId, double, out);
+  CHECK_ARGS(args, kTensorsDataId, double, out);
+
+  int id = static_cast<int>(args.get(kId).get<double>());
+  int tensors_data_id = static_cast<int>(args.get(kTensorsDataId).get<double>());
+
+  TensorsData* in_tensors_data = GetTensorsDataManager().GetTensorsData(tensors_data_id);
+  if (nullptr == in_tensors_data) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsData error"), &out,
+                      ("Could not find TensorsData handle with given id: %d", tensors_data_id));
+    return;
+  }
+
+  TensorsData* out_tensors_data = nullptr;
+  auto ret = single_manager_.Invoke(id, in_tensors_data, &out_tensors_data);
+  if (!ret) {
+    ReportError(ret, &out);
+    return;
+  }
+
+  out[kTensorsDataId] = picojson::value(static_cast<double>(out_tensors_data->Id()));
+  out[kTensorsInfoId] = picojson::value(static_cast<double>(out_tensors_data->TensorsInfoId()));
+  ReportSuccess(out);
+}
 
 void MlInstance::MLSingleShotGetValue(const picojson::value& args, picojson::object& out) {
   ScopeLogger("args: %s", args.serialize().c_str());
index 88b71af..3366b3e 100644 (file)
@@ -75,7 +75,7 @@ class MlInstance : public common::ParsedInstance {
   void MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out);
   void MLSingleShotGetTensorsInfo(const picojson::value& args, picojson::object& out);
   void MLSingleShotSetInputInfo(const picojson::value& args, picojson::object& out);
-  // SingleShot::invoke()
+  void MLSingleShotInvoke(const picojson::value& args, picojson::object& out);
   void MLSingleShotGetValue(const picojson::value& args, picojson::object& out);
   void MLSingleShotSetValue(const picojson::value& args, picojson::object& out);
   // SingleShot::setTimeout()
index 68c262b..a460a14 100644 (file)
@@ -50,7 +50,7 @@ PlatformResult SingleManager::OpenModel(const std::string& modelPath, TensorsInf
 
   std::lock_guard<std::mutex> singles_lock(singles_mutex_);
   int id = nextId_++;
-  singles_[id] = std::make_unique<SingleShot>(id, handle);
+  singles_[id] = std::make_unique<SingleShot>(id, handle, isDynamicMode);
   *res_id = id;
   return PlatformResult{};
 }
@@ -106,7 +106,43 @@ PlatformResult SingleManager::SetNativeInputInfo(int id, TensorsInfo* inTensorsI
   return PlatformResult{};
 }
 
-// SingleShot::invoke()
+PlatformResult SingleManager::Invoke(int id, TensorsData* in_tensors_data,
+                                     TensorsData** out_tensors_data) {
+  ScopeLogger();
+
+  SingleShot* single = GetSingleShot(id);
+  if (!single) {
+    LoggerE("Could not find SingleShot handle");
+    return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error");
+  }
+
+  ml_tensors_info_h out_tensors_info_h = nullptr;
+  ml_tensors_data_h out_tensors_data_h = nullptr;
+  bool should_copy_data = false;
+  PlatformResult result =
+      single->Invoke(in_tensors_data->Handle(), in_tensors_data->GetTensorsInfo()->Handle(),
+                     &out_tensors_data_h, &out_tensors_info_h, &should_copy_data);
+  if (!result) {
+    return result;
+  }
+  if (should_copy_data) {
+    *out_tensors_data = tim_->CloneNativeTensorWithData(out_tensors_info_h, out_tensors_data_h);
+  } else {
+    *out_tensors_data = tim_->CreateTensorsData(out_tensors_info_h, out_tensors_data_h);
+  }
+
+  if (*out_tensors_data == nullptr) {
+    LoggerE("out_tensors_data creation failed");
+    result = single->CleanUpAfterInvoke();
+    if (!result) {
+      LoggerE("CleanUpAfterInvoke failed");
+    }
+    return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error");
+  }
+
+  return PlatformResult{};
+}
+
 PlatformResult SingleManager::GetValue(int id, const std::string& name, std::string& value) {
   ScopeLogger();
 
index ad232aa..18d5aa0 100644 (file)
@@ -47,7 +47,7 @@ class SingleManager {
   // OpenModelSuccessCallback
   PlatformResult GetNativeTensorsInfo(int id, bool get_input_mode, int* res_id);
   PlatformResult SetNativeInputInfo(int id, TensorsInfo* inTensorsInfo);
-  // SingleShot::invoke()
+  PlatformResult Invoke(int id, TensorsData* in_tensors_data, TensorsData** out_tensors_data);
   PlatformResult GetValue(int id, const std::string& name, std::string& value);
   PlatformResult SetValue(int id, const std::string& name, const std::string& value);
   // SingleShot::setTimeout()
index 7459242..d7cc4d1 100644 (file)
@@ -26,18 +26,41 @@ using common::ErrorCode;
 namespace extension {
 namespace ml {
 
-SingleShot::SingleShot(int id, ml_single_h handle) : id_{id}, handle_{handle} {
+SingleShot::SingleShot(int id, ml_single_h handle, bool dynamic_mode)
+    : id_{id},
+      handle_{handle},
+      dynamic_mode_{dynamic_mode},
+      tensor_data_out_handle_{nullptr},
+      tensor_info_out_handle_{nullptr} {
   ScopeLogger("id: %d", id_);
 }
 
 // 'this' owns a handle_, and invalidates 'o'
-SingleShot::SingleShot(SingleShot&& o) : id_(o.id_), handle_(o.handle_) {
+SingleShot::SingleShot(SingleShot&& o)
+    : id_(o.id_), handle_(o.handle_), dynamic_mode_(o.dynamic_mode_) {
   ScopeLogger("id: %d", id_);
   o.handle_ = nullptr;
 }
 
 SingleShot::~SingleShot() {
   ScopeLogger("id: %d", id_);
+  // not dynamic mode uses ml_single_invoke_fast, which reuses handles, so they need to be freed
+  if (!dynamic_mode_) {
+    if (nullptr != tensor_data_out_handle_) {
+      int ret = ml_tensors_data_destroy(tensor_data_out_handle_);
+      if (ML_ERROR_NONE != ret) {
+        LoggerW("ml_tensors_data_destroy failed: %d (%s)", ret, get_error_message(ret));
+      }
+    }
+
+    if (nullptr != tensor_info_out_handle_) {
+      int ret = ml_tensors_info_destroy(tensor_info_out_handle_);
+      if (ML_ERROR_NONE != ret) {
+        LoggerW("ml_tensors_info_destroy failed: %d (%s)", ret, get_error_message(ret));
+      }
+    }
+  }
+
   int ret = ml_single_close(handle_);
   if (ML_ERROR_NONE != ret) {
     LoggerW("ml_single_close failed: %d (%s)", ret, get_error_message(ret));
@@ -75,7 +98,96 @@ PlatformResult SingleShot::SetInputInfo(ml_tensors_info_h in_info) {
   return PlatformResult{};
 }
 
-// SingleShot::invoke()
+PlatformResult SingleShot::Invoke(ml_tensors_data_h in_data, ml_tensors_info_h in_info,
+                                  ml_tensors_data_h* out_data, ml_tensors_info_h* out_info,
+                                  bool* should_copy_data) {
+  ScopeLogger();
+  PlatformResult result;
+  if (dynamic_mode_) {
+    result = InvokeDynamicInternal(in_data, in_info);
+  } else {
+    result = InvokeInternal(in_data, in_info);
+  }
+  if (!result) {
+    return result;
+  }
+
+  *out_data = tensor_data_out_handle_;
+  *out_info = tensor_info_out_handle_;
+  *should_copy_data = !dynamic_mode_;
+
+  return PlatformResult{};
+}
+
+PlatformResult SingleShot::InvokeInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info) {
+  ScopeLogger();
+  if (nullptr == tensor_info_out_handle_) {
+    PlatformResult result = GetTensorsInfo(false, &tensor_info_out_handle_);
+    if (!result) {
+      LoggerE("GetTensorsInfo failed");
+      return result;
+    }
+  }
+
+  if (nullptr == tensor_data_out_handle_) {
+    int ret = ml_tensors_data_create(tensor_info_out_handle_, &tensor_data_out_handle_);
+    if (ML_ERROR_NONE != ret) {
+      LoggerE("ml_tensors_data_create failed: %d (%s)", ret, get_error_message(ret));
+      return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error");
+    }
+  }
+
+  int ret = ml_single_invoke_fast(handle_, in_data, tensor_data_out_handle_);
+  if (ML_ERROR_NONE != ret) {
+    LoggerE("ml_single_invoke failed: %d (%s)", ret, get_error_message(ret));
+    return util::ToPlatformResult(ret, "Failed to invoke");
+  }
+  return PlatformResult{};
+}
+
+PlatformResult SingleShot::InvokeDynamicInternal(ml_tensors_data_h in_data,
+                                                 ml_tensors_info_h in_info) {
+  ScopeLogger();
+  int ret = ml_single_invoke_dynamic(handle_, in_data, in_info, &tensor_data_out_handle_,
+                                     &tensor_info_out_handle_);
+  if (ML_ERROR_NONE != ret) {
+    LoggerE("ml_single_invoke_dynamic failed: %d (%s)", ret, get_error_message(ret));
+    return util::ToPlatformResult(ret, "Failed to invoke");
+  }
+
+  return PlatformResult{};
+}
+
+PlatformResult SingleShot::CleanUpAfterInvoke() {
+  ScopeLogger();
+  if (dynamic_mode_) {
+    bool is_ok = true;
+    if (nullptr != tensor_data_out_handle_) {
+      int ret = ml_tensors_data_destroy(tensor_data_out_handle_);
+      if (ML_ERROR_NONE != ret) {
+        is_ok = false;
+        LoggerE("ml_tensors_data_destroy failed: %d (%s)", ret, get_error_message(ret));
+      } else {
+        tensor_data_out_handle_ = nullptr;
+      }
+    }
+
+    if (nullptr != tensor_info_out_handle_) {
+      int ret = ml_tensors_info_destroy(tensor_info_out_handle_);
+      if (ML_ERROR_NONE != ret) {
+        is_ok = false;
+        LoggerE("ml_tensors_info_destroy failed: %d (%s)", ret, get_error_message(ret));
+      } else {
+        tensor_info_out_handle_ = nullptr;
+      }
+    }
+    if (!is_ok) {
+      return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error");
+    }
+  }
+
+  return PlatformResult{};
+}
 
 PlatformResult SingleShot::GetValue(const std::string& name, std::string& value) {
   ScopeLogger();
index e456baf..32a831e 100644 (file)
@@ -31,7 +31,7 @@ namespace ml {
 
 class SingleShot {
  public:
-  SingleShot(int id, ml_single_h handle);
+  SingleShot(int id, ml_single_h handle, bool dynamic_mode);
   SingleShot() = delete;
   // copy semantics
   SingleShot(const SingleShot&) = delete;
@@ -43,8 +43,10 @@ class SingleShot {
 
   PlatformResult GetTensorsInfo(bool get_input_mode, ml_tensors_info_h* result);
   PlatformResult SetInputInfo(ml_tensors_info_h in_info);
-  // SingleShot::invoke()
-
+  PlatformResult Invoke(ml_tensors_data_h in_data, ml_tensors_info_h in_info,
+                        ml_tensors_data_h* out_data, ml_tensors_info_h* out_info,
+                        bool* should_copy_data);
+  PlatformResult CleanUpAfterInvoke();
   PlatformResult GetValue(const std::string& name, std::string& value);
   PlatformResult SetValue(const std::string& name, const std::string& value);
 
@@ -53,8 +55,14 @@ class SingleShot {
   // SingleShot::close()
 
  private:
+  PlatformResult InvokeInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info);
+  PlatformResult InvokeDynamicInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info);
   const int id_;
   ml_single_h handle_;
+  const bool dynamic_mode_;
+  // below handles are reused by ml_single_invoke_fast when dynamic mode is off
+  ml_tensors_data_h tensor_data_out_handle_;
+  ml_tensors_info_h tensor_info_out_handle_;
 };
 
 }  // namespace ml
index dd7d774..949a390 100644 (file)
@@ -325,6 +325,22 @@ TensorsDataManager::~TensorsDataManager() {
   map_.clear();
 };
 
+TensorsData* TensorsDataManager::CreateTensorsData(TensorsInfo* tensors_info,
+                                                   ml_tensors_data_h tensors_data_handle) {
+  ScopeLogger();
+  if (nullptr == tensors_info) {
+    LoggerE("Could not find tensor");
+    return nullptr;
+  }
+
+  std::lock_guard<std::mutex> lock{map_and_next_id_mutex_};
+  int id = nextId_++;
+  auto t = std::make_unique<TensorsData>(tensors_data_handle, id, tensors_info);
+  map_[id] = std::move(t);
+
+  return map_[id].get();
+}
+
 TensorsData* TensorsDataManager::CreateTensorsData(TensorsInfo* tensors_info) {
   ScopeLogger();
   if (nullptr == tensors_info) {
index af1067c..12f5da0 100644 (file)
@@ -100,6 +100,7 @@ class TensorsDataManager {
   ~TensorsDataManager();
 
   TensorsData* CreateTensorsData(TensorsInfo* tensors_info);
+  TensorsData* CreateTensorsData(TensorsInfo* tensors_info, ml_tensors_data_h tensors_data_handle);
   TensorsData* GetTensorsData(int id);
 
   PlatformResult DisposeTensorsData(int id);
index 0557ff8..46623df 100644 (file)
@@ -440,6 +440,15 @@ TensorsData* TensorsInfoManager::CreateTensorsData(TensorsInfo* tensors_info) {
   return tensors_data_manager_->CreateTensorsData(t_info);
 };
 
+TensorsData* TensorsInfoManager::CreateTensorsData(ml_tensors_info_h tensors_info_src,
+                                                   ml_tensors_data_h tensors_data_src) {
+  ScopeLogger("tensors_info_src: [%p], tensors_data_src: [%p]", tensors_info_src, tensors_data_src);
+
+  TensorsInfo* t_info = CreateTensorsInfo(tensors_info_src);
+
+  return tensors_data_manager_->CreateTensorsData(t_info, tensors_data_src);
+};
+
 TensorsData* TensorsInfoManager::CloneNativeTensorWithData(ml_tensors_info_h tensors_info_src,
                                                            ml_tensors_data_h tensors_data_src) {
   ScopeLogger("tensors_info_src: [%p], tensors_data_src: [%p]", tensors_info_src, tensors_data_src);
index 2a36d05..38a03b1 100644 (file)
@@ -84,6 +84,8 @@ class TensorsInfoManager {
   PlatformResult DisposeTensorsInfo(TensorsInfo* t);
 
   TensorsData* CreateTensorsData(TensorsInfo* tensors_info);
+  TensorsData* CreateTensorsData(ml_tensors_info_h tensors_info_src,
+                                 ml_tensors_data_h tensors_data_src);
   TensorsData* CloneNativeTensorWithData(ml_tensors_info_h tensors_info_src,
                                          ml_tensors_data_h tensors_data_src);