From: Piotr Kosko/Tizen API (PLT) /SRPOL/Engineer/Samsung Electronics
Date: Wed, 23 Jun 2021 11:32:22 +0000 (+0200)
Subject: [ML][Single] Added InvokeAsync() implementation
X-Git-Tag: submit/tizen/20210628.105256~1^2
X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3e12d4f1adea2c66e27494061757da3ddc33e7cb;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git
[ML][Single] Added InvokeAsync() implementation
[ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-278
[Verification] Code compiles without errors.
TCT passrate of existing APIs didn't change.
Checked in chrome console with below snippets:
// initialize test data
model = tizen.ml.single.openModel("documents/model.tflite");
var tensorsInfo = new tizen.ml.TensorsInfo();
tensorsInfo.addTensorInfo("tensor", "UINT8", [3, 224, 224]);
var tensorsData = tensorsInfo.getTensorsData();
var tensorsInfoInvalid = new tizen.ml.TensorsInfo();
tensorsInfoInvalid.addTensorInfo("tensor", "UINT8", [3, 125, 125]);
var tensorsDataInvalid = tensorsInfoInvalid.getTensorsData();
function errorCallback(error) {
console.log(error);
}
function successCallback(tensorsDataOut) {
console.log("Inference finished successfully");
console.log(tensorsDataOut.getTensorRawData(0));
tensorsDataOut.dispose();
}
// success
// test1
model.invokeAsync(tensorsData, successCallback, errorCallback);
// test2
model.invokeAsync(tensorsData, successCallback);
// errors
// test3
model.invokeAsync(tensorsData); // TypeMismatchError - sync
// test4
model.invokeAsync(null, successCallback); // TypeMismatchError - sync
// test5
model.invokeAsync(tensorsDataInvalid, successCallback, errorCallback); // AbortError - async
// test6
model.setTimeout(1)
model.invokeAsync(tensorsData, successCallback, errorCallback); // TimeoutError - async
// clear tensorsData
tensorsData.dispose();
tensorsInfo.dispose();
// test7 - use of disposed tesnsorsData
model.invokeAsync(tensorsData, successCallback, errorCallback); // AbortError - sync
// clear other data
tensorsDataInvalid.dispose();
tensorsInfoInvalid.dispose();
model.close();
Change-Id: I59900d7bab9a76939e27d68cb2bcd5434f446b3d
---
diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js
index b9598d79..1ecbaf6e 100755
--- a/src/ml/js/ml_single.js
+++ b/src/ml/js/ml_single.js
@@ -331,6 +331,57 @@ SingleShot.prototype.invoke = function() {
return new TensorsData(result.tensorsDataId, result.tensorsInfoId);
};
+var ValidInvokeAsyncErrors = ['TimeoutError', 'NotSupportedError', 'AbortError'];
+SingleShot.prototype.invokeAsync = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'inTensorsData',
+ type: types_.PLATFORM_OBJECT,
+ values: TensorsData
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ native_.getErrorObjectAndValidate(
+ result,
+ ValidInvokeAsyncErrors,
+ AbortError
+ )
+ );
+ }, 0);
+ } else {
+ native_.callIfPossible(
+ args.successCallback,
+ new TensorsData(result.tensorsDataId, result.tensorsInfoId)
+ );
+ }
+ };
+
+ var nativeArgs = {
+ id: this._id,
+ tensorsDataId: args.inTensorsData._id,
+ async: true
+ };
+
+ var result = native_.call('MLSingleShotInvoke', nativeArgs, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObjectAndValidate(
+ result,
+ ValidInvokeAsyncErrors,
+ AbortError
+ );
+ }
+};
+
var GetSetValueValidExceptions = [
'AbortError',
'InvalidValuesError',
diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc
index c6be5415..5cd456c6 100644
--- a/src/ml/ml_instance.cc
+++ b/src/ml/ml_instance.cc
@@ -889,24 +889,56 @@ void MlInstance::MLSingleShotInvoke(const picojson::value& args, picojson::objec
int id = static_cast(args.get(kId).get());
int tensors_data_id = static_cast(args.get(kTensorsDataId).get());
+ bool async =
+ (args.contains(kAsync) && args.get(kAsync).is()) ? args.get(kAsync).get() : false;
TensorsData* in_tensors_data = GetTensorsDataManager().GetTensorsData(tensors_data_id);
+ if (async && in_tensors_data) {
+ // in case of async flow need to prevent destroying entry data during invoke
+ // from JS, creation of a copy
+ in_tensors_data = GetTensorsInfoManager().CreateTensorsData(in_tensors_data->GetTensorsInfo());
+ }
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;
- }
+ auto logic = [this, id, tensors_data_id, in_tensors_data, async](decltype(out) out) {
+ TensorsData* out_tensors_data = nullptr;
+ auto ret = single_manager_.Invoke(id, in_tensors_data, &out_tensors_data);
+ if (async) {
+ // in case of async flow, the in_tensor_data with underlying TensorsInfo
+ // was copied, thus need to be released here
+ GetTensorsInfoManager().DisposeTensorsInfo(in_tensors_data->GetTensorsInfo());
+ GetTensorsDataManager().DisposeTensorsData(in_tensors_data);
+ }
+ if (!ret) {
+ ReportError(ret, &out);
+ return;
+ }
- out[kTensorsDataId] = picojson::value(static_cast(out_tensors_data->Id()));
- out[kTensorsInfoId] = picojson::value(static_cast(out_tensors_data->TensorsInfoId()));
- ReportSuccess(out);
+ out[kTensorsDataId] = picojson::value(static_cast(out_tensors_data->Id()));
+ out[kTensorsInfoId] = picojson::value(static_cast(out_tensors_data->TensorsInfoId()));
+ ReportSuccess(out);
+ };
+
+ if (!async) {
+ logic(out);
+ } else {
+ CHECK_ARGS(args, kCallbackId, double, out);
+ double callback_id = args.get(kCallbackId).get();
+ this->worker_.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get();
+ async_out[kCallbackId] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
}
void MlInstance::MLSingleShotGetValue(const picojson::value& args, picojson::object& out) {