From 5037903948846cac5c9a9bb88f78ef1eba79fb4f Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Mon, 18 Jan 2021 15:19:54 +0100 Subject: [PATCH 01/16] [ML][Common] Add TensorsInfo.getTensorSize ACR: TWDAPI-273 Test code: var ti = new tizen.ml.TensorsInfo(); ti.addTensorInfo("tensor1", "UINT8", [1, 1]) console.log(ti.getTensorSize(0)) ti.addTensorInfo("tensor2", "UINT8", [2, 3, 4]) console.log(ti.getTensorSize(1)) ti.addTensorInfo("tensor2", "FLOAT32", [2, 3, 4]) console.log(ti.getTensorSize(2)) console.log(ti.getTensorSize(-1)) [Verification] Built successful. Tested in Chrome Dev console. Change-Id: I841da30d03a0590cea66ec6217130163a87f59ec Signed-off-by: Rafal Walczyna --- src/ml/js/ml_common.js | 30 +++++++++++++++++++++++++++++- src/ml/ml_instance.cc | 25 +++++++++++++++++++++++++ src/ml/ml_instance.h | 1 + 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 50f1f58..62be9ff 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -480,7 +480,35 @@ TensorsInfo.prototype.setTensorType = function() { TensorsInfo.prototype.getTensorSize = function() { _CheckIfTensorsInfoNotDisposed(this._id); - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + } + ]); + + if (!args.has.index) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: index is undefined' + ); + } + + var callArgs = { + index: args.index, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoGetTensorSize', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGettersSettersValidExceptions, + AbortError + ); + } + return native_.getResultObject(result); }; TensorsInfo.prototype.getTensorsData = function() { diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 2e35e2b..f1ce1f9 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -81,6 +81,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLTensorsInfoSetDimensions); REGISTER_METHOD(MLTensorsInfoGetTensorName); REGISTER_METHOD(MLTensorsInfoSetTensorName); + REGISTER_METHOD(MLTensorsInfoGetTensorSize); REGISTER_METHOD(MLTensorsInfoGetTensorType); REGISTER_METHOD(MLTensorsInfoSetTensorType); REGISTER_METHOD(MLTensorsInfoClone); @@ -368,6 +369,30 @@ void MlInstance::MLTensorsInfoSetTensorName(const picojson::value& args, picojso ReportSuccess(out); } +void MlInstance::MLTensorsInfoGetTensorSize(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + int index = static_cast(args.get(kIndex).get()); + size_t size; + PlatformResult result = tensorsInfo->NativeGetTensorSize(index, &size); + if (!result) { + LogAndReportError(result, &out); + return; + } + + picojson::value val = picojson::value{static_cast(size)}; + ReportSuccess(val, out); +} + void MlInstance::MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); CHECK_ARGS(args, kTensorsInfoId, double, out); diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 553ebce..08e6dc8 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -44,6 +44,7 @@ class MlInstance : public common::ParsedInstance { void MLTensorsInfoSetDimensions(const picojson::value& args, picojson::object& out); void MLTensorsInfoGetTensorName(const picojson::value& args, picojson::object& out); void MLTensorsInfoSetTensorName(const picojson::value& args, picojson::object& out); + void MLTensorsInfoGetTensorSize(const picojson::value& args, picojson::object& out); void MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out); void MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out); void MLTensorsInfoClone(const picojson::value& args, picojson::object& out); -- 2.7.4 From 1aa0933309c7eceed81314aaff40551e15225981 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Mon, 18 Jan 2021 20:35:14 +0100 Subject: [PATCH 02/16] [common] Add std::exception handler to ParsedInstance When an exception derived from std::exception and not PlatformException is thrown in webapi-plugins code, only the following error message was logged: HandleException(393) > Exception: Unknown exception As std::exception inheritance is a very common practice, especially in standard library, we add logging std::exception::what() message to make debugging easier. [Verification] An exception thrown from std::string is caught and its what() message is logged properly. Change-Id: I879ebe80b609cf26a7e68be822a783aa9ef145eb Signed-off-by: Pawel Wasowski --- src/common/extension.cc | 11 +++++++++++ src/common/extension.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/common/extension.cc b/src/common/extension.cc index 6a0a2c3..7a1be11 100644 --- a/src/common/extension.cc +++ b/src/common/extension.cc @@ -383,6 +383,8 @@ void ParsedInstance::HandleMessage(const char* msg, bool is_sync) { return HandleException(e); } catch (const PlatformException* e) { return HandleException(*e); + } catch (const std::exception& e) { + return HandleException(e); } catch (...) { return HandleException(UnknownException("Unknown exception")); } @@ -396,6 +398,15 @@ void ParsedInstance::HandleException(const PlatformException& ex) { SendSyncReply(result.serialize().c_str()); } +void ParsedInstance::HandleException(const std::exception& e) { + ScopeLogger(); + LoggerE("std::exception: %s", e.what()); + picojson::value result = picojson::value(picojson::object()); + ReportError(common::PlatformResult{common::ErrorCode::ABORT_ERR, "An unknown internal error"}, + &result.get()); + SendSyncReply(result.serialize().c_str()); +} + void ParsedInstance::HandleError(const PlatformResult& e) { LoggerE("Error: %d", static_cast(e.error_code())); picojson::value result = picojson::value(picojson::object()); diff --git a/src/common/extension.h b/src/common/extension.h index 404e3f7..99f459e 100644 --- a/src/common/extension.h +++ b/src/common/extension.h @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -142,6 +143,7 @@ class ParsedInstance : public Instance { void HandleMessage(const char* msg, bool is_sync); void HandleException(const PlatformException& ex); + void HandleException(const std::exception& e); void HandleError(const PlatformResult& error); std::map handler_map_; -- 2.7.4 From 909ab54575c0f8354bd2aa8bcffa75ed6e1eb93a Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Mon, 18 Jan 2021 22:11:55 +0100 Subject: [PATCH 03/16] [mediacontroller] Prevent undefined behavior Constructing a std::string from nullptr is undefined behavior and caused an exception after setting std=c++17 flag in GCC (no exception was thrown when compiling with std=c++14). This commit removes the UB. The problem caused MediaControllerServerInfo_iconURI_attribute test from tct-mediacontroller-tizen-tests failures. [Verification] auto tct-mediacontroller-tizen-tests 1. with std=c++14: 100% pass rate 2. with std=c++17: 100% pass rate Change-Id: I4857e3d9f8ba2940b50223e89ff952625ba37b3c Signed-off-by: Pawel Wasowski --- src/mediacontroller/mediacontroller_client.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mediacontroller/mediacontroller_client.cc b/src/mediacontroller/mediacontroller_client.cc index 6ff85f5..82d927d 100644 --- a/src/mediacontroller/mediacontroller_client.cc +++ b/src/mediacontroller/mediacontroller_client.cc @@ -554,9 +554,10 @@ PlatformResult MediaControllerClient::GetServerIconURI(const std::string& name, return PlatformResult(ErrorCode::UNKNOWN_ERR); } - *icon_uri = nullptr; if (nullptr != icon_uri_str) { *icon_uri = std::string(icon_uri_str); + } else { + *icon_uri = std::string{}; } return PlatformResult(ErrorCode::NO_ERROR); -- 2.7.4 From 687dc363d3f61052d695e425da69460d9faa2434 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 19 Jan 2021 02:36:44 +0100 Subject: [PATCH 04/16] [Datacontrol] Prevent crashes by purging code with undefined behavior The following line caused crashes: IdMap[info->requestId] = info.release(); Argument evaluation order was not strictly defined in C++ before C++17 - behavior of the expression above was undefined. C++17 introduced more strict rules and their implementation in GCC caused a crash after setting -std=c++17 - it seems, that info.release() would be now called before info->requestId. [Verification] tct-datacontrol-tizen-tests (auto, c++14 and c++17 build): 100% pass rate The snippet below crashed apps 100% times when webapi-plugins were compiled with C++17. Now, the snippet works fine var PROVIDER_ID = "http://tizen.org/datacontrol/provider/DictionaryDataControlProvider"; var DATA_ID = "Dictionary"; var TYPE_SQL = "SQL"; var TYPE_MAP = "MAP"; var globalDataControl = tizen.datacontrol.getDataControlConsumer(PROVIDER_ID, DATA_ID, TYPE_MAP); function successcb(id) { console.log("Ok: reqid " + id); } function errorcb(id, error) { console.log("Error id: " + id + ", error msg: " + error.message); } try { globalDataControl.addValue(123, "tizen", "Foo", successcb, errorcb); } catch (err) { console.log(err.name + ": " + err.message); } Change-Id: Ibd80f60d100a616b8a9607c27e9eebf8a64e7a10 --- src/datacontrol/datacontrol_instance.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/datacontrol/datacontrol_instance.cc b/src/datacontrol/datacontrol_instance.cc index d954fa7..1648896 100644 --- a/src/datacontrol/datacontrol_instance.cc +++ b/src/datacontrol/datacontrol_instance.cc @@ -490,7 +490,8 @@ int DatacontrolInstance::RunMAPDataControlJob(const std::string& providerId, result = job(handle, &info->requestId); RETURN_IF_FAIL(result, "Doing job failed with error"); - IdMap[info->requestId] = info.release(); + auto requestId = info->requestId; + IdMap[requestId] = info.release(); return result; } @@ -524,7 +525,8 @@ int DatacontrolInstance::RunSQLDataControlJob(const std::string& providerId, result = job(handle, &info->requestId); RETURN_IF_FAIL(result, "Doing job failed with error"); - IdMap[info->requestId] = info.release(); + auto requestId = info->requestId; + IdMap[requestId] = info.release(); return result; } -- 2.7.4 From 0695849438bca542cc877a2b343d94c8d8bd7c88 Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Wed, 20 Jan 2021 08:39:32 +0100 Subject: [PATCH 05/16] [ML] Added placeholders for further development [Verification] Code compiles without errors Change-Id: I2b69891c596e31ae87fb519b60aa3811e949c5d5 --- src/ml/js/ml_single.js | 18 +++++++++++++++++- src/ml/ml.gyp | 4 ++++ src/ml/ml_instance.cc | 30 ++++++++++++++++++++++++++++++ src/ml/ml_instance.h | 11 ++++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index 923af0a..f9aa0d8 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -16,4 +16,20 @@ var MachineLearningSingle = function() {}; -// ML Single API +// MachineLearningSingle::openModel() + +// MachineLearningSingle::openModelAsync() + +// OpenModelSuccessCallback + +// SingleShot interface (input & output) + +// SingleShot::invoke() + +// SingleShot::getValue() + +// SingleShot::setValue() + +// SingleShot::setTimeout() + +// SingleShot::close() diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index c959f43..a8fb82f 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -23,8 +23,12 @@ 'ml_pipeline_nodeinfo.h', 'ml_pipeline_switch.cc', 'ml_pipeline_switch.h', + #TODO pipeline Source + #TODO pipeline Valve 'ml_tensors_info_manager.cc', 'ml_tensors_info_manager.h', + #TODO single SingleShotManager + #TODO single SingleShot 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index f1ce1f9..1677d38 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -89,6 +89,16 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLTensorsInfoDispose); // Single API begin + // MachineLearningSingle::openModel() + // MachineLearningSingle::openModelAsync() + // OpenModelSuccessCallback + // SingleShot input + // SingleShot output + // SingleShot::invoke() + // SingleShot::getValue() + // SingleShot::setValue() + // SingleShot::setTimeout() + // SingleShot::close() // Single API end @@ -524,6 +534,26 @@ void MlInstance::MLTensorsInfoDispose(const picojson::value& args, picojson::obj // Single API begin +// MachineLearningSingle::openModel() + +// MachineLearningSingle::openModelAsync() + +// OpenModelSuccessCallback + +// SingleShot input + +// SingleShot output + +// SingleShot::invoke() + +// SingleShot::getValue() + +// SingleShot::setValue() + +// SingleShot::setTimeout() + +// SingleShot::close() + // Single API end // Pipeline API begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 08e6dc8..d511e8d 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -54,7 +54,16 @@ class MlInstance : public common::ParsedInstance { // Common ML API end // Single API begin - + // MachineLearningSingle::openModel() + // MachineLearningSingle::openModelAsync() + // OpenModelSuccessCallback + // SingleShot input + // SingleShot output + // SingleShot::invoke() + // SingleShot::getValue() + // SingleShot::setValue() + // SingleShot::setTimeout() + // SingleShot::close() // Single API end // Pipeline API begin -- 2.7.4 From 4010734b6b4ec9e26532c068adfbb8d24d92ab77 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Wed, 20 Jan 2021 12:49:15 +0100 Subject: [PATCH 06/16] [ML][Common] Add support for creating TensorsInfo from native handle ACR: TWDAPI-273 Some of the ml native functions require not initialized handle. TensorsInfo::CreateTensorsInfo() uses ml_tensors_info_create which allocates memory for tensors info - but i.e. ml_single_get_input_info allocates memory again without freeing old handle. [Verification] Builts successfully, TensorsInfo.count tested in Chrome dev console. Change-Id: I6b2e9c60dbed23a2d1962e68cc9408a8faecb383 Signed-off-by: Rafal Walczyna --- src/ml/ml_tensors_info_manager.cc | 23 +++++++++++++++++++++-- src/ml/ml_tensors_info_manager.h | 2 ++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ml/ml_tensors_info_manager.cc b/src/ml/ml_tensors_info_manager.cc index 33af06f..8947aa6 100644 --- a/src/ml/ml_tensors_info_manager.cc +++ b/src/ml/ml_tensors_info_manager.cc @@ -24,7 +24,7 @@ using common::PlatformResult; namespace extension { namespace ml { -TensorsInfo::TensorsInfo(ml_tensors_info_h handle, int id) : handle_(handle), id_(id), count_(0) { +TensorsInfo::TensorsInfo(ml_tensors_info_h handle, int id) : handle_(handle), id_(id), count_(-1) { ScopeLogger(); } @@ -42,6 +42,15 @@ int TensorsInfo::Id() { } int TensorsInfo::Count() { + if (-1 == count_) { + LoggerD("Lazy initialization of count_ property."); + unsigned int c; + if (NativeGetCount(&c)) { + count_ = c; + } else { + LoggerE("Could not fetch TensorsInfo count from native layer"); + } + } return this->count_; } @@ -98,7 +107,6 @@ std::shared_ptr TensorsInfo::CreateClone(int cloneId) { return nullptr; } auto t = std::make_shared(clone_h, cloneId); - t->count_ = this->Count(); return t; } @@ -301,6 +309,17 @@ TensorsInfo* TensorsInfoManager::CreateTensorsInfo() { return t.get(); }; +TensorsInfo* TensorsInfoManager::CreateTensorsInfo(ml_tensors_info_h handle) { + ScopeLogger(); + + int id = nextId_++; + auto t = std::make_shared(handle, id); + map_by_id_[id] = t; + map_by_handle_[handle] = t; + + return t.get(); +}; + TensorsInfo* TensorsInfoManager::CloneTensorsInfo(TensorsInfo* src) { ScopeLogger(); if (nullptr == src) { diff --git a/src/ml/ml_tensors_info_manager.h b/src/ml/ml_tensors_info_manager.h index d1d8b3c..6320216 100644 --- a/src/ml/ml_tensors_info_manager.h +++ b/src/ml/ml_tensors_info_manager.h @@ -69,6 +69,8 @@ class TensorsInfoManager { TensorsInfoManager(); ~TensorsInfoManager(); TensorsInfo* CreateTensorsInfo(); + // handle will be destroyed on TensorsInfo object destruction + TensorsInfo* CreateTensorsInfo(ml_tensors_info_h handle); TensorsInfo* CloneTensorsInfo(TensorsInfo* src); TensorsInfo* GetTensorsInfo(int id); -- 2.7.4 From c138b52bf1801ad5b086e911e056945040f30204 Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Wed, 20 Jan 2021 14:29:50 +0100 Subject: [PATCH 07/16] [Common] Moved convertUriToPath to common::tools convertingUriToPath is used in few modules and usage of one version of this function will be beneficial. [Verification] TCT exif, package, metadata 100% pass. Change-Id: Ifbca0fa3a83de0757faa30b214e4b298c4678789 --- src/common/tools.cc | 21 +++++++++++++++++++++ src/common/tools.h | 2 ++ src/exif/exif_instance.cc | 6 +++--- src/exif/exif_util.cc | 35 ----------------------------------- src/exif/exif_util.h | 3 --- src/exif/get_exif_info.cc | 3 ++- src/metadata/metadata_file_handle.cc | 32 ++++---------------------------- src/metadata/metadata_instance.cc | 2 +- src/package/package_instance.cc | 35 +---------------------------------- 9 files changed, 34 insertions(+), 105 deletions(-) diff --git a/src/common/tools.cc b/src/common/tools.cc index 6e79ee6..2d87122 100644 --- a/src/common/tools.cc +++ b/src/common/tools.cc @@ -596,5 +596,26 @@ std::string ConvertToLowerCase(const std::string& input_string) { return output_string; } +std::string ltrim(const std::string& s) { + ScopeLogger(); + std::string str = s; + auto pos = str.find_first_not_of(" "); + str.erase(0, pos); + return str; +} + +std::string ConvertUriToPath(const std::string& str) { + const std::string URI_PREFIX = "file://"; + ScopeLogger(); + std::string path = ltrim(str); + std::string prefix = path.substr(0, URI_PREFIX.size()); + + if (prefix == URI_PREFIX) { + return path.substr(URI_PREFIX.size()); + } else { + return path; + } +} + } // namespace tools } // namespace common diff --git a/src/common/tools.h b/src/common/tools.h index 17e1e98..84df727 100644 --- a/src/common/tools.h +++ b/src/common/tools.h @@ -121,6 +121,8 @@ void PrintDeprecationWarningFor(const char* className, const char* replacement = std::string ConvertToLowerCase(const std::string& input_string); +std::string ConvertUriToPath(const std::string& uri); + } // namespace tools } // namespace common diff --git a/src/exif/exif_instance.cc b/src/exif/exif_instance.cc index b0cf17c..6bae127 100644 --- a/src/exif/exif_instance.cc +++ b/src/exif/exif_instance.cc @@ -63,7 +63,7 @@ void ExifInstance::ExifManagerGetExifInfo(const picojson::value& args, picojson: ScopeLogger(); const std::string& uri = args.get("uri").get(); - const std::string& file_path = ExifUtil::convertUriToPath(uri); + const std::string& file_path = common::tools::ConvertUriToPath(uri); const double callback_id = args.get("callbackId").get(); const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path); @@ -108,7 +108,7 @@ void ExifInstance::ExifManagerSaveExifInfo(const picojson::value& args, picojson const double callback_id = args.get("callbackId").get(); const std::string& file_uri = args.get("uri").get(); - const std::string& file_path = ExifUtil::convertUriToPath(file_uri); + const std::string& file_path = common::tools::ConvertUriToPath(file_uri); const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path); CHECK_STORAGE_ACCESS(real_path, &out); @@ -143,7 +143,7 @@ void ExifInstance::ExifManagerGetThumbnail(const picojson::value& args, picojson ScopeLogger(); const std::string& uri = args.get("uri").get(); - const std::string& file_path = ExifUtil::ExifUtil::convertUriToPath(uri); + const std::string& file_path = common::tools::ConvertUriToPath(uri); const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path); CHECK_STORAGE_ACCESS(real_path, &out); diff --git a/src/exif/exif_util.cc b/src/exif/exif_util.cc index ebf2c0a..2737c1f 100644 --- a/src/exif/exif_util.cc +++ b/src/exif/exif_util.cc @@ -49,8 +49,6 @@ const std::string EXPOSURE_PROGRAM_PORTRAIT_MODE = "PORTRAIT_MODE"; const std::string EXPOSURE_PROGRAM_LANDSCAPE_MODE = "LANDSCAPE_MODE"; const std::string DUMMY = ""; // For unexpected input handling - -const std::string URI_PREFIX = "file://"; } // namespace const std::size_t ExifTypeInfo::ByteSize = 1; @@ -213,39 +211,6 @@ const std::string& ExifUtil::exposureProgramToString(ExposureProgram value) { } } -// Example: -// in: uri = file://TZ_USER_IMAGES/exif.jpg -// out: path = TZ_USER_IMAGES/exif.jpg -std::string ExifUtil::convertUriToPath(const std::string& str) { - ScopeLogger(); - std::string path = ltrim(str); - std::string prefix = path.substr(0, URI_PREFIX.size()); - - if (prefix == URI_PREFIX) { - return path.substr(URI_PREFIX.size()); - } else { - return path; - } -} - -std::string ExifUtil::ltrim(const std::string& s) { - ScopeLogger(); - std::string str = s; - std::string::iterator i; - for (i = str.begin(); i != str.end(); ++i) { - if (!isspace(*i)) { - break; - } - } - - if (i == str.end()) { - str.clear(); - } else { - str.erase(str.begin(), i); - } - return str; -} - time_t ExifUtil::exifDateTimeOriginalToTimeT(const char* string) { ScopeLogger(); int year, month, day, hour, min, sec; diff --git a/src/exif/exif_util.h b/src/exif/exif_util.h index 1dab85a..e816f29 100644 --- a/src/exif/exif_util.h +++ b/src/exif/exif_util.h @@ -114,9 +114,6 @@ class ExifUtil { static ExposureProgram stringToExposureProgram(const std::string& exposure_program); static const std::string& exposureProgramToString(ExposureProgram value); - static std::string convertUriToPath(const std::string& str); - static std::string ltrim(const std::string& s); - static time_t exifDateTimeOriginalToTimeT(const char* string); static std::string timeTToExifDateTimeOriginal(time_t time); static const Rationals timeTToExifGpsTimeStamp(time_t time); diff --git a/src/exif/get_exif_info.cc b/src/exif/get_exif_info.cc index 4cd21c4..34e1cf8 100644 --- a/src/exif/get_exif_info.cc +++ b/src/exif/get_exif_info.cc @@ -23,6 +23,7 @@ #include "common/logger.h" #include "common/platform_result.h" +#include "common/tools.h" #include "exif/exif_util.h" @@ -468,7 +469,7 @@ void GetExifInfo::DataForeachFunction(ExifContent* content, void* user_data) { PlatformResult GetExifInfo::LoadFromURI(const std::string& uri, JsonValue* result) { ScopeLogger(); - const std::string& file_path = ExifUtil::convertUriToPath(uri); + const std::string& file_path = common::tools::ConvertUriToPath(uri); ExifData* ed = exif_data_new_from_file(file_path.c_str()); if (!ed) { return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error reading exif from file", diff --git a/src/metadata/metadata_file_handle.cc b/src/metadata/metadata_file_handle.cc index 2dfe002..71a01ed 100644 --- a/src/metadata/metadata_file_handle.cc +++ b/src/metadata/metadata_file_handle.cc @@ -22,6 +22,7 @@ #include "common/platform_enum.h" #include "common/platform_exception.h" #include "common/scope_exit.h" +#include "common/tools.h" namespace extension { namespace metadata { @@ -81,33 +82,8 @@ PlatformResult convertErrorCode(int err) { } } -std::string ltrim(const std::string& s) { - ScopeLogger(); - std::string str = s; - std::string::iterator i; - for (i = str.begin(); i != str.end(); ++i) { - if (!isspace(*i)) { - break; - } - } - str.erase(str.begin(), i); - return str; -} - -std::string convertUriToPath(const std::string& str) { - const std::string URI_PREFIX = "file://"; - ScopeLogger(); - std::string path = ltrim(str); - std::string prefix = path.substr(0, URI_PREFIX.size()); - - if (prefix == URI_PREFIX) { - return path.substr(URI_PREFIX.size()); - } else { - return path; - } -} - -MetadataFileHandle::MetadataFileHandle(int id) : handle_(nullptr), id_(id), width_(0), height_(0), lyrics_num_(0) { +MetadataFileHandle::MetadataFileHandle(int id) + : handle_(nullptr), id_(id), width_(0), height_(0), lyrics_num_(0) { ScopeLogger(); } @@ -145,7 +121,7 @@ MetadataFileHandle::~MetadataFileHandle() { PlatformResult MetadataFileHandle::Initialize(const std::string& uri) { ScopeLogger(); - auto path = convertUriToPath(uri); + auto path = common::tools::ConvertUriToPath(uri); int result = metadata_extractor_create(&handle_); if (METADATA_EXTRACTOR_ERROR_NONE != result) { diff --git a/src/metadata/metadata_instance.cc b/src/metadata/metadata_instance.cc index 36d6fdf..e06dca5 100644 --- a/src/metadata/metadata_instance.cc +++ b/src/metadata/metadata_instance.cc @@ -155,7 +155,7 @@ void MetadataInstance::MetadataFileHandleGetArtwork(const picojson::value& args, } void MetadataInstance::MetadataFileHandleGetThumbnailFrame(const picojson::value& args, - picojson::object& out) { + picojson::object& out) { ScopeLogger(); const std::string& uri = args.get("uri").get(); const int id = static_cast(args.get("id").get()); diff --git a/src/package/package_instance.cc b/src/package/package_instance.cc index c1779c6..0613621 100644 --- a/src/package/package_instance.cc +++ b/src/package/package_instance.cc @@ -184,39 +184,6 @@ static void PackageListenerCb(const char* type, const char* package, } } -static std::string ltrim(const std::string& s) { - ScopeLogger(); - std::string str = s; - std::string::iterator i; - for (i = str.begin(); i != str.end(); ++i) { - if (!isspace(*i)) { - break; - } - } - if (i == str.end()) { - str.clear(); - } else { - str.erase(str.begin(), i); - } - return str; -} - -static std::string convertUriToPath(const std::string& uri) { - ScopeLogger(); - std::string result; - std::string schema("file://"); - std::string str = ltrim(uri); - - std::string _schema = str.substr(0, schema.size()); - if (_schema == schema) { - result = str.substr(schema.size()); - } else { - result = str; - } - - return result; -} - PackageInstance::PackageInstance() { ScopeLogger(); @@ -303,7 +270,7 @@ void PackageInstance::PackageManagerInstall(const picojson::value& args, picojso int callback_id = static_cast(args.get("callbackId").get()); const std::string& packageFileURI = - convertUriToPath(args.get("packageFileURI").get()); + common::tools::ConvertUriToPath(args.get("packageFileURI").get()); int progress_callback_id = static_cast(args.get("progressCallbackId").get()); const std::string real_path = common::FilesystemProvider::Create().GetRealPath(packageFileURI); -- 2.7.4 From b9e041a03c7d6ed56e49d2f3d5017e7498f5095a Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Wed, 20 Jan 2021 16:49:03 +0100 Subject: [PATCH 08/16] [ML][pipeline] Implement Pipeline::getValve() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ACR: TWDAPI-274 [Verification] Tested in Chrome DevTools with the below snippets, works fine. var pipeline_def = "videotestsrc is-live=true ! videoconvert ! videoscale" + " ! video/x-raw,format=RGBx,width=16,height=16,framerate=10/1" + " ! tensor_converter ! valve name=valve1 ! fakesink"; var pipeline = tizen.ml.pipeline.createPipeline(pipeline_def, function(state) {console.log(state);}); pipeline.getValve('valve1') // alve {name: "valve1", _pipeline_id: 1} pipeline.getValve('valve_XXX') // WebAPIException {code: 0, name: "InvalidValuesError", ... pipeline.getValve() // WebAPIException {code: 0, name: "InvalidValuesError", ... Change-Id: Id11414f80c42a9879532dfc1c651f766c4f12834 Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 41 ++++++++++++++++++++++++ src/ml/ml.gyp | 3 +- src/ml/ml_instance.cc | 17 ++++++++++ src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 18 +++++++++++ src/ml/ml_pipeline.h | 10 +++--- src/ml/ml_pipeline_manager.cc | 10 ++++++ src/ml/ml_pipeline_manager.h | 2 +- src/ml/ml_pipeline_valve.cc | 72 +++++++++++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline_valve.h | 53 +++++++++++++++++++++++++++++++ 10 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 src/ml/ml_pipeline_valve.cc create mode 100644 src/ml/ml_pipeline_valve.h diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index 6ca9366..ad745f1 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -261,7 +261,48 @@ Pipeline.prototype.getSwitch = function() { //Pipeline::getSwitch() end //Pipeline::getValve() begin +function Valve(name, pipeline_id) { + Object.defineProperties(this, { + name: { + enumerable: true, + value: name + }, + _pipeline_id: { + value: pipeline_id + } + }); +} +var ValidPipelineGetValveExceptions = [ + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; +Pipeline.prototype.getValve = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + } + ]); + + var nativeArgs = { + name: args.name, + id: this._id + }; + + var result = native_.callSync('MLPipelineGetValve', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineGetValveExceptions, + AbortError + ); + } + + return new Valve(nativeArgs.name, this._id); +}; //Pipeline::getValve() end //Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index a8fb82f..cc6c5b8 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -24,7 +24,8 @@ 'ml_pipeline_switch.cc', 'ml_pipeline_switch.h', #TODO pipeline Source - #TODO pipeline Valve + 'ml_pipeline_valve.h', + 'ml_pipeline_valve.cc', 'ml_tensors_info_manager.cc', 'ml_tensors_info_manager.h', #TODO single SingleShotManager diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 1c7edcf..01837ef 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -113,6 +113,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLPipelineGetSwitch); REGISTER_METHOD(MLPipelineSwitchGetPadList); REGISTER_METHOD(MLPipelineSwitchSelect); + REGISTER_METHOD(MLPipelineGetValve); // Pipeline API end #undef REGISTER_METHOD @@ -760,7 +761,23 @@ void MlInstance::MLPipelineGetSwitch(const picojson::value& args, picojson::obje // Pipeline::getSwitch() end // Pipeline::getValve() begin +void MlInstance::MLPipelineGetValve(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kName, std::string, out); + + auto name = args.get(kName).get(); + auto pipeline_id = args.get(kId).get(); + auto ret = pipeline_manager_.GetValve(name, pipeline_id); + if (!ret) { + LogAndReportError(ret, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 31ccde5..a79076a 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -102,7 +102,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::getSwitch() end // Pipeline::getValve() begin - + void MLPipelineGetValve(const picojson::value& args, picojson::object& out); // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index ded7436..11ec31a 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -194,6 +194,8 @@ PlatformResult Pipeline::Dispose() { node_info_.clear(); + valves_.clear(); + auto ret = ml_pipeline_destroy(pipeline_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); @@ -257,7 +259,23 @@ PlatformResult Pipeline::GetSwitch(const std::string& name, std::string* type) { // Pipeline::getSwitch() end // Pipeline::getValve() begin +PlatformResult Pipeline::GetValve(const std::string& name) { + ScopeLogger("id: [%d], name: [%s]", id_, name.c_str()); + + auto valve_it = valves_.find(name); + if (valves_.end() != valve_it) { + LoggerD("Valve [%s] found", name.c_str()); + return PlatformResult{}; + } + LoggerD("Creating [%s] Valve", name.c_str()); + std::unique_ptr valve_ptr; + auto ret = Valve::CreateValve(name, pipeline_, &valve_ptr); + if (ret) { + valves_.insert({name, std::move(valve_ptr)}); + } + return ret; +} // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index fda943a..110cec9 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -28,6 +28,7 @@ #include "common/platform_result.h" #include "ml_pipeline_nodeinfo.h" #include "ml_pipeline_switch.h" +#include "ml_pipeline_valve.h" using common::PlatformResult; using namespace extension::ml::pipeline; @@ -83,7 +84,7 @@ class Pipeline { // Pipeline::getSwitch() end // Pipeline::getValve() begin - + PlatformResult GetValve(const std::string& name); // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin @@ -141,13 +142,14 @@ class Pipeline { */ /* - * As switch controls the flow of the data in the pipeline - * and users could potentially want to access it - * often, we use unordered_map instead of a map for quick + * As switch/valve control the flow of the data in the pipeline + * and users could potentially want to access them + * often, we use unordered_maps instead of a maps for quick * retrieval. */ std::unordered_map> switches_; std::map> node_info_; + std::unordered_map> valves_; static void PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data); }; diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index 3ee54e3..a403200 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -163,7 +163,17 @@ PlatformResult PipelineManager::GetSwitch(const std::string& name, int pipeline_ // Pipeline::getSwitch() end // Pipeline::getValve() begin +PlatformResult PipelineManager::GetValve(const std::string& name, int pipeline_id) { + ScopeLogger("name: [%s], pipeline_id: [%d]", name.c_str(), pipeline_id); + + auto pipeline_it = pipelines_.find(pipeline_id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", pipeline_id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + return pipeline_it->second->GetValve(name); +} // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 668933a..666887f 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -72,7 +72,7 @@ class PipelineManager { // Pipeline::getSwitch() end // Pipeline::getValve() begin - + PlatformResult GetValve(const std::string& name, int pipeline_id); // Pipeline::getValve() end // Pipeline::registerSinkCallback() begin diff --git a/src/ml/ml_pipeline_valve.cc b/src/ml/ml_pipeline_valve.cc new file mode 100644 index 0000000..cbd6fda --- /dev/null +++ b/src/ml/ml_pipeline_valve.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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. + */ + +#include "ml_pipeline_valve.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { +namespace pipeline { + +PlatformResult Valve::CreateValve(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out) { + ScopeLogger("name: [%s], pipeline: [%p]", name.c_str(), pipeline); + + ml_pipeline_valve_h valve_handle = nullptr; + auto ret = ml_pipeline_valve_get_handle(pipeline, name.c_str(), &valve_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_valve_get_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get valve"); + } + LoggerD("ml_pipeline_valve_get_handle() succeeded"); + + out->reset(new (std::nothrow) Valve{name, valve_handle}); + if (!out) { + ret = ml_pipeline_valve_release_handle(valve_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_valve_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_valve_release_handle() succeeded"); + } + return LogAndCreateResult(ErrorCode::ABORT_ERR, "Could not get the valve", + ("Could not allocate memory")); + } + + return PlatformResult{}; +} + +Valve::Valve(const std::string& name, ml_pipeline_valve_h valve_handle) + : name_{name}, valve_{valve_handle} { + ScopeLogger("name: [%s], handle: [%p]", name.c_str(), valve_handle); +} + +Valve::~Valve() { + ScopeLogger("name: [%s], handle: [%p]", name_.c_str(), valve_); + + auto ret = ml_pipeline_valve_release_handle(valve_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_valve_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_valve_release_handle() succeeded"); + } +} + +} // namespace pipeline +} // namespace ml +} // namespace extension \ No newline at end of file diff --git a/src/ml/ml_pipeline_valve.h b/src/ml/ml_pipeline_valve.h new file mode 100644 index 0000000..a03e0e7 --- /dev/null +++ b/src/ml/ml_pipeline_valve.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 ML_ML_PIPELINE_VALVE_H_ +#define ML_ML_PIPELINE_VALVE_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { +namespace pipeline { + +class Valve { + public: + static PlatformResult CreateValve(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out); + + ~Valve(); + + Valve(const Valve&) = delete; + Valve& operator=(const Valve&) = delete; + + private: + Valve(const std::string& name, ml_pipeline_valve_h valve_handle); + const std::string name_; + const ml_pipeline_valve_h valve_; +}; + +} // namespace pipeline +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_VALVE_H_ \ No newline at end of file -- 2.7.4 From 7893a78315c5207492b21c153c14c28246751fad Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Wed, 20 Jan 2021 11:55:36 +0100 Subject: [PATCH 09/16] [ML][Single] Added manager file and implementation for openModel() [ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-273 [Verification] Code compiles without errors. Checked in chrome console with few calls: Success calls: tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite") tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite", null, null, "TENSORFLOW_LITE") tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite", null, null, "TENSORFLOW_LITE", "ANY", true) Fail for invalid or not-existing file: tizen.ml.single.openModel("documents/fail.tflite") // Abort Error tizen.ml.single.openModel("documents/notexisting") // NotFound tizen.ml.single.openModel("notexisting") // NotFound Change-Id: I8b2b89e60d8f265185d3ddcafcc224f4e5c15fa1 --- src/ml/js/ml_single.js | 79 +++++++++++++++++++++++++++++++++++++++++++ src/ml/ml.gyp | 6 ++-- src/ml/ml_instance.cc | 82 +++++++++++++++++++++++++++++++++++++++++++-- src/ml/ml_instance.h | 4 ++- src/ml/ml_single_manager.cc | 68 +++++++++++++++++++++++++++++++++++++ src/ml/ml_single_manager.h | 61 +++++++++++++++++++++++++++++++++ src/ml/ml_singleshot.cc | 61 +++++++++++++++++++++++++++++++++ src/ml/ml_singleshot.h | 66 ++++++++++++++++++++++++++++++++++++ 8 files changed, 422 insertions(+), 5 deletions(-) create mode 100644 src/ml/ml_single_manager.cc create mode 100644 src/ml/ml_single_manager.h create mode 100644 src/ml/ml_singleshot.cc create mode 100644 src/ml/ml_singleshot.h diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index f9aa0d8..22cf5ba 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -17,12 +17,91 @@ var MachineLearningSingle = function() {}; // MachineLearningSingle::openModel() +var ValidOpenModelExceptions = [ + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'SecurityError', + 'AbortError' +]; + +var NO_ID = -1; +MachineLearningSingle.prototype.openModel = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'modelPath', + type: types_.STRING + }, + { + name: 'inTensorsInfo', + type: types_.PLATFORM_OBJECT, + values: TensorsInfo, + optional: true, + nullable: true + }, + { + name: 'outTensorsInfo', + type: types_.PLATFORM_OBJECT, + values: TensorsInfo, + optional: true, + nullable: true + }, + { + name: 'fwType', + type: types_.ENUM, + values: Object.keys(NNFWType), + optional: true + }, + { + name: 'hwType', + type: types_.ENUM, + values: Object.keys(HWType), + optional: true + }, + { + name: 'isDynamicMode', + type: types_.BOOLEAN, + optional: true + } + ]); + try { + // get normalized URI of a file + args.modelPath = tizen.filesystem.toURI(args.modelPath); + } catch (e) { + throw new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Path is invalid'); + } + + var nativeArgs = { + modelPath: args.modelPath, + inTensorsInfo: args.inTensorsInfo ? args.inTensorsInfo._id : NO_ID, + outTensorsInfo: args.outTensorsInfo ? args.outTensorsInfo._id : NO_ID, + fwType: args.fwType ? args.fwType : 'ANY', + hwType: args.hwType ? args.hwType : 'ANY', + isDynamicMode: args.isDynamicMode ? args.isDynamicMode : false + }; + + var result = native_.callSync('MLSingleManagerOpenModel', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidOpenModelExceptions, + AbortError + ); + } + + return new SingleShot(result.id); +}; // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback // SingleShot interface (input & output) +var SingleShot = function(id) { + Object.defineProperties(this, { + _id: { value: id, writable: false, enumerable: false } + }); +}; // SingleShot::invoke() diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index a8fb82f..62490a5 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -27,8 +27,10 @@ #TODO pipeline Valve 'ml_tensors_info_manager.cc', 'ml_tensors_info_manager.h', - #TODO single SingleShotManager - #TODO single SingleShot + 'ml_single_manager.cc', + 'ml_single_manager.h', + 'ml_singleshot.cc', + 'ml_singleshot.h', 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 1677d38..260b3c3 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -21,6 +21,7 @@ #include "common/logger.h" #include "common/picojson.h" #include "common/platform_result.h" +#include "common/tools.h" namespace extension { namespace ml { @@ -89,7 +90,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLTensorsInfoDispose); // Single API begin - // MachineLearningSingle::openModel() + REGISTER_METHOD(MLSingleManagerOpenModel); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback // SingleShot input @@ -534,7 +535,84 @@ void MlInstance::MLTensorsInfoDispose(const picojson::value& args, picojson::obj // Single API begin -// MachineLearningSingle::openModel() +// TODO move to the up section with field names +namespace { +const std::string kModelPath = "modelPath"; +const std::string kInTensorsInfo = "inTensorsInfo"; +const std::string kOutTensorsInfo = "outTensorsInfo"; +const std::string kFwType = "fwType"; +const std::string kHwType = "hwType"; +const std::string kIsDynamicMode = "isDynamicMode"; + +const int kNoId = -1; +} // namespace +void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kModelPath, std::string, out); + CHECK_ARGS(args, kInTensorsInfo, double, out); + CHECK_ARGS(args, kOutTensorsInfo, double, out); + CHECK_ARGS(args, kFwType, std::string, out); + CHECK_ARGS(args, kHwType, std::string, out); + CHECK_ARGS(args, kIsDynamicMode, bool, out); + + const auto& model_path = common::tools::ConvertUriToPath(args.get(kModelPath).get()); + PlatformResult result = common::tools::CheckFileAvailability(model_path); + if (!result) { + LogAndReportError( + PlatformResult(ErrorCode::NOT_FOUND_ERR, "File does not exist or is not accessible"), &out, + ("File does not exist or is not accessible: %s", model_path.c_str())); + return; + } + + TensorsInfo* in_tensors_info = nullptr; + auto inTensorId = static_cast(args.get(kInTensorsInfo).get()); + if (kNoId != inTensorId) { + in_tensors_info = GetTensorsInfoManager().GetTensorsInfo(inTensorId); + if (nullptr == in_tensors_info) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", inTensorId)); + return; + } + } + + TensorsInfo* out_tensors_info = nullptr; + auto outTensorId = static_cast(args.get(kOutTensorsInfo).get()); + if (kNoId != outTensorId) { + out_tensors_info = GetTensorsInfoManager().GetTensorsInfo(outTensorId); + if (nullptr == out_tensors_info) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", outTensorId)); + return; + } + } + + ml_nnfw_type_e nnfw_e = ML_NNFW_TYPE_ANY; + result = types::NNFWTypeEnum.getValue(args.get(kFwType).get(), &nnfw_e); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ml_nnfw_hw_e hw_e = ML_NNFW_HW_ANY; + result = types::HWTypeEnum.getValue(args.get(kHwType).get(), &hw_e); + if (!result) { + LogAndReportError(result, &out); + return; + } + + auto is_dynamic_mode = args.get(kIsDynamicMode).get(); + + int res_id = -1; + result = single_manager_.OpenModel(model_path, in_tensors_info, out_tensors_info, nnfw_e, hw_e, + is_dynamic_mode, &res_id); + if (!result) { + ReportError(result, &out); + return; + } + + out["id"] = picojson::value(static_cast(res_id)); + ReportSuccess(out); +} // MachineLearningSingle::openModelAsync() diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index d511e8d..5afbba3 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -20,6 +20,7 @@ #include "common/extension.h" #include "ml/ml_pipeline_manager.h" +#include "ml/ml_single_manager.h" #include "nnstreamer/nnstreamer-single.h" #include "nnstreamer/nnstreamer.h" @@ -54,7 +55,8 @@ class MlInstance : public common::ParsedInstance { // Common ML API end // Single API begin - // MachineLearningSingle::openModel() + SingleManager single_manager_; + void MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback // SingleShot input diff --git a/src/ml/ml_single_manager.cc b/src/ml/ml_single_manager.cc new file mode 100644 index 0000000..00f813f --- /dev/null +++ b/src/ml/ml_single_manager.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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. + */ + +#include "ml_single_manager.h" +#include "common/tools.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { + +SingleManager::SingleManager() : nextId_{0} { + ScopeLogger(); +} + +SingleManager::~SingleManager() { + ScopeLogger(); +} + +// MachineLearningSingle::openModel() +PlatformResult SingleManager::OpenModel(const std::string& modelPath, TensorsInfo* inTensorsInfo, + TensorsInfo* outTensorsInfo, ml_nnfw_type_e nnfw_e, + ml_nnfw_hw_e hw_e, bool isDynamicMode, int* res_id) { + ScopeLogger(); + + ml_single_h handle = nullptr; + + ml_tensors_info_h in_info = inTensorsInfo ? inTensorsInfo->Handle() : nullptr; + ml_tensors_info_h out_info = outTensorsInfo ? outTensorsInfo->Handle() : nullptr; + + int ret = ml_single_open(&handle, modelPath.c_str(), in_info, out_info, nnfw_e, hw_e); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_single_open failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to open model"); + } + + int id = nextId_++; + singles_[id] = std::make_unique(id, handle); + *res_id = id; + return PlatformResult{}; +} + +// MachineLearningSingle::openModelAsync() +// OpenModelSuccessCallback +// SingleShot input +// SingleShot output +// SingleShot::invoke() +// SingleShot::getValue() +// SingleShot::setValue() +// SingleShot::setTimeout() +// SingleShot::close() + +} // namespace ml +} // namespace extension diff --git a/src/ml/ml_single_manager.h b/src/ml/ml_single_manager.h new file mode 100644 index 0000000..034fbff --- /dev/null +++ b/src/ml/ml_single_manager.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 ML_ML_SINGLE_MANAGER_H_ +#define ML_ML_SINGLE_MANAGER_H_ + +#include "common/platform_result.h" + +#include "ml_singleshot.h" +#include "ml_tensors_info_manager.h" +#include "nnstreamer/nnstreamer-single.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { + +class SingleManager { + public: + SingleManager(); + ~SingleManager(); + + SingleManager(const SingleManager&) = delete; + SingleManager& operator=(const SingleManager&) = delete; + + // MachineLearningSingle::openModel() + PlatformResult OpenModel(const std::string& modelPath, TensorsInfo* inTensorsInfo, + TensorsInfo* outTensorsInfo, ml_nnfw_type_e nnfw_e, ml_nnfw_hw_e hw_e, + bool isDynamicMode, int* res_id); + // MachineLearningSingle::openModelAsync() + // OpenModelSuccessCallback + // SingleShot input + // SingleShot output + // SingleShot::invoke() + // SingleShot::getValue() + // SingleShot::setValue() + // SingleShot::setTimeout() + // SingleShot::close() + + private: + int nextId_; + std::map> singles_; +}; + +} // namespace ml +} // namespace extension + +#endif // ML_ML_SINGLE_MANAGER_H_ diff --git a/src/ml/ml_singleshot.cc b/src/ml/ml_singleshot.cc new file mode 100644 index 0000000..a9fb3a0 --- /dev/null +++ b/src/ml/ml_singleshot.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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. + */ +#include + +#include "common/logger.h" +#include "ml_singleshot.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { + +SingleShot::SingleShot(int id, ml_single_h handle) : id_{id}, handle_{handle} { + ScopeLogger("id: %d", id_); +} + +// 'this' owns a handle_, and invalidates 'o' +SingleShot::SingleShot(SingleShot&& o) : id_(o.id_), handle_(o.handle_) { + ScopeLogger("id: %d", id_); + o.handle_ = nullptr; +} + +SingleShot::~SingleShot() { + ScopeLogger("id: %d", id_); + int ret = ml_single_close(handle_); + if (ML_ERROR_NONE != ret) { + LoggerW("ml_single_close failed: %d (%s)", ret, get_error_message(ret)); + } +} + +// SingleShot input + +// SingleShot output + +// SingleShot::invoke() + +// SingleShot::getValue() + +// SingleShot::setValue() + +// SingleShot::setTimeout() + +// SingleShot::close() + +} // namespace extension +} // namespace ml diff --git a/src/ml/ml_singleshot.h b/src/ml/ml_singleshot.h new file mode 100644 index 0000000..0a02b0e --- /dev/null +++ b/src/ml/ml_singleshot.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 ML_ML_SINGLESHOT_H_ +#define ML_ML_SINGLESHOT_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { + +class SingleShot { + public: + SingleShot(int id, ml_single_h handle); + SingleShot() = delete; + // copy semantics + SingleShot(const SingleShot&) = delete; + SingleShot& operator=(const SingleShot&) = delete; + // move semantics + SingleShot(SingleShot&& o); + SingleShot& operator=(SingleShot&& o) = delete; + ~SingleShot(); + + // SingleShot input + + // SingleShot output + + // SingleShot::invoke() + + // SingleShot::getValue() + + // SingleShot::setValue() + + // SingleShot::setTimeout() + + // SingleShot::close() + + private: + const int id_; + ml_single_h handle_; +}; + +} // namespace ml +} // namespace extension + +#endif // ML_ML_SINGLESHOT_H_ -- 2.7.4 From efd1b8a69bf615d00f42d69a90e72663d3662fd4 Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Thu, 21 Jan 2021 13:09:41 +0100 Subject: [PATCH 10/16] [ML][Single] Implemented SingleShot.input member - get [ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-273 [Verification] Code compiles without errors. Checked in Chrome console: // open model var model = tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite") // all implemented members of input work model.input.getDimensions(0) Change-Id: I132d5e6262f7142c8040c7f40f69f11a1ef63827 --- src/ml/js/ml_single.js | 20 ++++++++++++++++++++ src/ml/ml_instance.cc | 20 ++++++++++++++++++-- src/ml/ml_instance.h | 2 +- src/ml/ml_single_manager.cc | 31 ++++++++++++++++++++++++++++++- src/ml/ml_single_manager.h | 7 +++++-- src/ml/ml_singleshot.cc | 13 ++++++++++++- src/ml/ml_singleshot.h | 2 +- 7 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index 22cf5ba..e79731d 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -97,8 +97,28 @@ MachineLearningSingle.prototype.openModel = function() { // OpenModelSuccessCallback // SingleShot interface (input & output) +var ValidInputExceptions = ['TypeMismatch', 'AbortError']; var SingleShot = function(id) { Object.defineProperties(this, { + input: { + get: function() { + var result = native_.callSync('MLSingleShotGetInputInfo', { + id: this._id + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInputExceptions, + AbortError + ); + } + + return new TensorsInfo(result.id); + }, + set: function(v) { + /* TODO*/ + } + }, _id: { value: id, writable: false, enumerable: false } }); }; diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index d2171de..9fe0111 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -68,7 +68,7 @@ using namespace common; CHECK_EXIST(args, name, out) \ CHECK_TYPE(args, name, type, out) -MlInstance::MlInstance() : pipeline_manager_{this} { +MlInstance::MlInstance() : single_manager_{&tensors_info_manager_}, pipeline_manager_{this} { ScopeLogger(); using namespace std::placeholders; @@ -94,7 +94,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLSingleManagerOpenModel); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - // SingleShot input + REGISTER_METHOD(MLSingleShotGetInputInfo); // SingleShot output // SingleShot::invoke() // SingleShot::getValue() @@ -623,6 +623,22 @@ void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson: // OpenModelSuccessCallback // SingleShot input +void MlInstance::MLSingleShotGetInputInfo(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kId, double, out); + + auto id = static_cast(args.get(kId).get()); + + int res_id = -1; + auto ret = single_manager_.GetNativeInputInfo(id, &res_id); + if (!ret) { + ReportError(ret, &out); + return; + } + + out["id"] = picojson::value(static_cast(res_id)); + ReportSuccess(out); +} // SingleShot output diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index ebcb32f..9619647 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -59,7 +59,7 @@ class MlInstance : public common::ParsedInstance { void MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - // SingleShot input + void MLSingleShotGetInputInfo(const picojson::value& args, picojson::object& out); // SingleShot output // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_single_manager.cc b/src/ml/ml_single_manager.cc index 00f813f..0bb6a0a 100644 --- a/src/ml/ml_single_manager.cc +++ b/src/ml/ml_single_manager.cc @@ -23,7 +23,7 @@ using common::ErrorCode; namespace extension { namespace ml { -SingleManager::SingleManager() : nextId_{0} { +SingleManager::SingleManager(TensorsInfoManager* tim) : nextId_{0}, tim_{tim} { ScopeLogger(); } @@ -57,6 +57,35 @@ PlatformResult SingleManager::OpenModel(const std::string& modelPath, TensorsInf // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback // SingleShot input +SingleShot* SingleManager::GetSingleShot(int id) { + ScopeLogger("id: %d", id); + + if (singles_.end() != singles_.find(id)) { + return singles_[id].get(); + } + + return nullptr; +} + +PlatformResult SingleManager::GetNativeInputInfo(int id, int* res_id) { + ScopeLogger(); + + SingleShot* single = GetSingleShot(id); + if (!single) { + LoggerE("Could not find singleShot handle"); + return PlatformResult(ErrorCode::ABORT_ERR); + } + + ml_tensors_info_h in_info = nullptr; + PlatformResult ret = single->GetInputInfo(&in_info); + if (!ret) { + return ret; + } + + auto tensor_info = tim_->CreateTensorsInfo(in_info); + *res_id = tensor_info->Id(); + return PlatformResult{}; +} // SingleShot output // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_single_manager.h b/src/ml/ml_single_manager.h index 034fbff..8dc3804 100644 --- a/src/ml/ml_single_manager.h +++ b/src/ml/ml_single_manager.h @@ -30,9 +30,10 @@ namespace ml { class SingleManager { public: - SingleManager(); + SingleManager(TensorsInfoManager* tim); ~SingleManager(); + SingleManager() = delete; SingleManager(const SingleManager&) = delete; SingleManager& operator=(const SingleManager&) = delete; @@ -42,7 +43,7 @@ class SingleManager { bool isDynamicMode, int* res_id); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - // SingleShot input + PlatformResult GetNativeInputInfo(int id, int* res_id); // SingleShot output // SingleShot::invoke() // SingleShot::getValue() @@ -53,6 +54,8 @@ class SingleManager { private: int nextId_; std::map> singles_; + TensorsInfoManager* tim_; + SingleShot* GetSingleShot(int id); }; } // namespace ml diff --git a/src/ml/ml_singleshot.cc b/src/ml/ml_singleshot.cc index a9fb3a0..6fbe25c 100644 --- a/src/ml/ml_singleshot.cc +++ b/src/ml/ml_singleshot.cc @@ -43,7 +43,18 @@ SingleShot::~SingleShot() { } } -// SingleShot input +PlatformResult SingleShot::GetInputInfo(ml_tensors_info_h* result) { + ScopeLogger(); + ml_tensors_info_h info = nullptr; + int ret = ml_single_get_input_info(handle_, &info); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_single_get_input_info failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor dimension"); + } + + *result = info; + return PlatformResult{}; +} // SingleShot output diff --git a/src/ml/ml_singleshot.h b/src/ml/ml_singleshot.h index 0a02b0e..eb174f0 100644 --- a/src/ml/ml_singleshot.h +++ b/src/ml/ml_singleshot.h @@ -41,7 +41,7 @@ class SingleShot { SingleShot& operator=(SingleShot&& o) = delete; ~SingleShot(); - // SingleShot input + PlatformResult GetInputInfo(ml_tensors_info_h* result); // SingleShot output -- 2.7.4 From bf07405c394a22aa3b0af1a12b0a463fb3e5e58a Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Fri, 22 Jan 2021 08:27:53 +0100 Subject: [PATCH 11/16] [ML][Single] Implemented SingleShot.output member - get [ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-273 [Verification] Code compiles without errors. Checked in Chrome console: // open model var model = tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite") // below works well model.input.getDimensions(0) model.output.getDimensions(0) Change-Id: I43120610873a455eb813bb02db9c3eeff7a02e91 --- src/ml/js/ml_single.js | 27 ++++++++++++++++++++++++--- src/ml/ml_instance.cc | 20 ++++++++++++-------- src/ml/ml_instance.h | 3 +-- src/ml/ml_single_manager.cc | 6 +++--- src/ml/ml_single_manager.h | 3 +-- src/ml/ml_singleshot.cc | 17 +++++++++++------ src/ml/ml_singleshot.h | 4 +--- 7 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index e79731d..40a00de 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -97,13 +97,14 @@ MachineLearningSingle.prototype.openModel = function() { // OpenModelSuccessCallback // SingleShot interface (input & output) -var ValidInputExceptions = ['TypeMismatch', 'AbortError']; +var ValidInputExceptions = ['TypeMismatchError', 'AbortError']; var SingleShot = function(id) { Object.defineProperties(this, { input: { get: function() { - var result = native_.callSync('MLSingleShotGetInputInfo', { - id: this._id + var result = native_.callSync('MLSingleShotGetTensorsInfo', { + id: this._id, + getInputMode: true // true means gathering input information }); if (native_.isFailure(result)) { throw native_.getErrorObjectAndValidate( @@ -119,6 +120,26 @@ var SingleShot = function(id) { /* TODO*/ } }, + output: { + get: function() { + var result = native_.callSync('MLSingleShotGetTensorsInfo', { + id: this._id, + getInputMode: false // false means gathering output information + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInputExceptions, + AbortError + ); + } + + return new TensorsInfo(result.id); + }, + set: function(v) { + /* readonly */ + } + }, _id: { value: id, writable: false, enumerable: false } }); }; diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 9fe0111..b56fcbc 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -94,8 +94,7 @@ MlInstance::MlInstance() : single_manager_{&tensors_info_manager_}, pipeline_man REGISTER_METHOD(MLSingleManagerOpenModel); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - REGISTER_METHOD(MLSingleShotGetInputInfo); - // SingleShot output + REGISTER_METHOD(MLSingleShotGetTensorsInfo); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() @@ -608,7 +607,7 @@ void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson: int res_id = -1; result = single_manager_.OpenModel(model_path, in_tensors_info, out_tensors_info, nnfw_e, hw_e, - is_dynamic_mode, &res_id); + is_dynamic_mode, &res_id); if (!result) { ReportError(result, &out); return; @@ -622,15 +621,22 @@ void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson: // OpenModelSuccessCallback -// SingleShot input -void MlInstance::MLSingleShotGetInputInfo(const picojson::value& args, picojson::object& out) { +// SingleShot input/output +// TODO move to the up section with field names +namespace { +const std::string kGetInputMode = "getInputMode"; +} // namespace +void MlInstance::MLSingleShotGetTensorsInfo(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kGetInputMode, bool, out); auto id = static_cast(args.get(kId).get()); + // true means gathering input data; false means gathering output data + auto get_input_mode = static_cast(args.get(kGetInputMode).get()); int res_id = -1; - auto ret = single_manager_.GetNativeInputInfo(id, &res_id); + auto ret = single_manager_.GetNativeTensorsInfo(id, get_input_mode, &res_id); if (!ret) { ReportError(ret, &out); return; @@ -640,8 +646,6 @@ void MlInstance::MLSingleShotGetInputInfo(const picojson::value& args, picojson: ReportSuccess(out); } -// SingleShot output - // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 9619647..5488f76 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -59,8 +59,7 @@ class MlInstance : public common::ParsedInstance { void MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - void MLSingleShotGetInputInfo(const picojson::value& args, picojson::object& out); - // SingleShot output + void MLSingleShotGetTensorsInfo(const picojson::value& args, picojson::object& out); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_single_manager.cc b/src/ml/ml_single_manager.cc index 0bb6a0a..4bc3d1a 100644 --- a/src/ml/ml_single_manager.cc +++ b/src/ml/ml_single_manager.cc @@ -67,7 +67,7 @@ SingleShot* SingleManager::GetSingleShot(int id) { return nullptr; } -PlatformResult SingleManager::GetNativeInputInfo(int id, int* res_id) { +PlatformResult SingleManager::GetNativeTensorsInfo(int id, bool get_input_mode, int* res_id) { ScopeLogger(); SingleShot* single = GetSingleShot(id); @@ -77,7 +77,7 @@ PlatformResult SingleManager::GetNativeInputInfo(int id, int* res_id) { } ml_tensors_info_h in_info = nullptr; - PlatformResult ret = single->GetInputInfo(&in_info); + PlatformResult ret = single->GetTensorsInfo(get_input_mode, &in_info); if (!ret) { return ret; } @@ -86,7 +86,7 @@ PlatformResult SingleManager::GetNativeInputInfo(int id, int* res_id) { *res_id = tensor_info->Id(); return PlatformResult{}; } -// SingleShot output + // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_single_manager.h b/src/ml/ml_single_manager.h index 8dc3804..bf98373 100644 --- a/src/ml/ml_single_manager.h +++ b/src/ml/ml_single_manager.h @@ -43,8 +43,7 @@ class SingleManager { bool isDynamicMode, int* res_id); // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback - PlatformResult GetNativeInputInfo(int id, int* res_id); - // SingleShot output + PlatformResult GetNativeTensorsInfo(int id, bool get_input_mode, int* res_id); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_singleshot.cc b/src/ml/ml_singleshot.cc index 6fbe25c..beff9f1 100644 --- a/src/ml/ml_singleshot.cc +++ b/src/ml/ml_singleshot.cc @@ -43,21 +43,26 @@ SingleShot::~SingleShot() { } } -PlatformResult SingleShot::GetInputInfo(ml_tensors_info_h* result) { +PlatformResult SingleShot::GetTensorsInfo(bool get_input_mode, ml_tensors_info_h* result) { ScopeLogger(); ml_tensors_info_h info = nullptr; - int ret = ml_single_get_input_info(handle_, &info); + int ret = 0; + if (get_input_mode) { + ret = ml_single_get_input_info(handle_, &info); + } else { + ret = ml_single_get_output_info(handle_, &info); + } if (ML_ERROR_NONE != ret) { - LoggerE("ml_single_get_input_info failed: %d (%s)", ret, get_error_message(ret)); - return util::ToPlatformResult(ret, "Failed to get tensor dimension"); + LoggerE("%s failed: %d (%s)", + get_input_mode ? "ml_single_get_input_info" : "ml_single_get_output_info", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensors info"); } *result = info; return PlatformResult{}; } -// SingleShot output - // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_singleshot.h b/src/ml/ml_singleshot.h index eb174f0..a78d955 100644 --- a/src/ml/ml_singleshot.h +++ b/src/ml/ml_singleshot.h @@ -41,9 +41,7 @@ class SingleShot { SingleShot& operator=(SingleShot&& o) = delete; ~SingleShot(); - PlatformResult GetInputInfo(ml_tensors_info_h* result); - - // SingleShot output + PlatformResult GetTensorsInfo(bool get_input_mode, ml_tensors_info_h* result); // SingleShot::invoke() -- 2.7.4 From 3ff361e26e286119dc48448e02710ffad2e859d2 Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Wed, 20 Jan 2021 13:48:43 +0100 Subject: [PATCH 12/16] [ML][Pipeline] Implementation setProperty and getProperty ACR: TWDAPI-274 [Verification] Code compiles without error. Tested in chrome console. // test code var pipeline = tizen.ml.pipeline.createPipeline("videotestsrc name=vsrc is-live=true ! videoconvert ! videoscale name=vscale ! video/x-raw,format=RGBx,width=224,height=224,framerate=60/1 ! tensor_converter ! valve name=valvex ! input-selector name=is01 ! tensor_sink name=sinkx") //BOOLEAN var nodeinfo_bool = pipeline.getNodeInfo("is01") nodeinfo_bool.setProperty("sync-streams", "BOOLEAN", true) nodeinfo_bool.getProperty("sync-streams", "BOOLEAN") nodeinfo_bool.setProperty("sync-streams", "BOOLEAN", false) nodeinfo_bool.getProperty("sync-streams", "BOOLEAN") //DOUBLE var nodeinfo_double = pipeline.getNodeInfo("vscale") nodeinfo_double.setProperty("sharpness", "DOUBLE", 0.72) nodeinfo_double.getProperty("sharpness", "DOUBLE") //INT32 var nodeinfo_int32 = pipeline.getNodeInfo("vsrc") nodeinfo_int32.setProperty("kx", "INT32", 10) nodeinfo_int32.getProperty("kx", "INT32") //UINT32 var nodeinfo_uint32 = pipeline.getNodeInfo("vsrc") nodeinfo_uint32.setProperty("foreground-color", "UINT32", 123456) nodeinfo_uint32.getProperty("foreground-color", "UINT32") //INT64 var nodeinfo_int64 = pipeline.getNodeInfo("vsrc") nodeinfo_int64.setProperty("timestamp-offset", "INT64", 10) nodeinfo_int64.getProperty("timestamp-offset", "INT64") //UINT64 var pipeline_uint64 = tizen.ml.pipeline.createPipeline("udpsrc name=usrc port=5555 caps=application/x-rtp ! queue ! fakesink") var nodeinfo_uint64 = pipeline_uint64.getNodeInfo("usrc") nodeinfo_uint64.setProperty("timeout", "UINT64", 166513216516510) nodeinfo_uint64.getProperty("timeout", "UINT64") //STRING var pipeline_string = tizen.ml.pipeline.createPipeline("videotestsrc ! video/x-raw,format=RGB,width=640,height=480 ! videorate max-rate=1 ! tensor_converter ! tensor_mux ! tensor_demux name=demux ! tensor_sink") var nodeinfo_string = pipeline_string.getNodeInfo("demux") nodeinfo_string.setProperty("tensorpick", "STRING", "1,2") nodeinfo_string.getProperty("tensorpick", "STRING") // ENUM var vscale_enum = { GST_VIDEO_SCALE_NEAREST:0, GST_VIDEO_SCALE_BILINEAR:1, GST_VIDEO_SCALE_4TAP:2, GST_VIDEO_SCALE_LANCZOS:3 } var pipeline_enum = tizen.ml.pipeline.createPipeline("videotestsrc name=vsrc is-live=true ! videoconvert ! videoscale name=vscale ! video/x-raw,format=RGBx,width=224,height=224,framerate=60/1 ! tensor_converter ! valve name=valvex ! input-selector name=is01 ! tensor_sink name=sinkx") var nodeinfo_enum = pipeline_enum.getNodeInfo("vscale") nodeinfo_enum.setProperty("method", "ENUM", vscale_enum.GST_VIDEO_SCALE_4TAP) nodeinfo_enum.getProperty("method", "ENUM") Change-Id: I90f9a3986beeb6a071ce4b265965eec399679c55 Signed-off-by: Lukasz Bardeli --- src/ml/js/ml_pipeline.js | 87 +++++++++++++++++++ src/ml/ml_instance.cc | 85 ++++++++++++++----- src/ml/ml_instance.h | 4 +- src/ml/ml_pipeline.cc | 29 ++++++- src/ml/ml_pipeline.h | 6 +- src/ml/ml_pipeline_manager.cc | 26 ++++++ src/ml/ml_pipeline_manager.h | 6 +- src/ml/ml_pipeline_nodeinfo.cc | 184 ++++++++++++++++++++++++++++++++++++++++- src/ml/ml_pipeline_nodeinfo.h | 7 +- 9 files changed, 401 insertions(+), 33 deletions(-) diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index ad745f1..425e34c 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -321,12 +321,99 @@ Pipeline.prototype.getValve = function() { //Pipeline::unregisterCustomFilter() end +var PropertyType = { + BOOLEAN: 'BOOLEAN', + DOUBLE: 'DOUBLE', + ENUM: 'ENUM', + INT32: 'INT32', + INT64: 'INT64', + UINT32: 'UINT32', + UINT64: 'UINT64', + STRING: 'STRING' +}; //NodeInfo::getProperty() begin +var ValidNodeInfoGetPropertyExceptions = [ + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'TypeMismatchError', + 'AbortError' +]; +NodeInfo.prototype.getProperty = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + }, + { + name: 'propertyType', + type: types_.ENUM, + values: Object.keys(PropertyType) + } + ]); + + var nativeArgs = { + id: this._pipeline_id, + nodeName: this.name, + name: args.name, + type: args.propertyType + }; + + var result = native_.callSync('MLPipelineNodeInfoGetProperty', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidNodeInfoGetPropertyExceptions, + AbortError + ); + } + return result.property; +}; //NodeInfo::getProperty() end //NodeInfo::setProperty() begin +var ValidNodeInfoSetPropertyExceptions = [ + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'TypeMismatchError', + 'AbortError' +]; +NodeInfo.prototype.setProperty = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + }, + { + name: 'propertyType', + type: types_.ENUM, + values: Object.keys(PropertyType) + }, + { + name: 'property', + type: types_.SIMPLE_TYPE + } + ]); + + var nativeArgs = { + id: this._pipeline_id, + nodeName: this.name, + name: args.name, + type: args.propertyType, + property: args.property + }; + var result = native_.callSync('MLPipelineNodeInfoSetProperty', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidNodeInfoSetPropertyExceptions, + AbortError + ); + } +}; //NodeInfo::setProperty() end //Source::inputTensorsInfo begin diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 9fe0111..50d04e6 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -39,6 +39,10 @@ const std::string kDefinition = "definition"; const std::string kPipelineStateChangeListenerName = "listenerName"; const std::string kOtherId = "otherId"; const std::string kPadName = "padName"; +const std::string kNodeName = "nodeName"; +const std::string kProperty = "property"; +const std::string kBOOLEAN = "BOOLEAN"; +const std::string kSTRING = "STRING"; } // namespace using namespace common; @@ -115,6 +119,8 @@ MlInstance::MlInstance() : single_manager_{&tensors_info_manager_}, pipeline_man REGISTER_METHOD(MLPipelineSwitchGetPadList); REGISTER_METHOD(MLPipelineSwitchSelect); REGISTER_METHOD(MLPipelineGetValve); + REGISTER_METHOD(MLPipelineNodeInfoGetProperty); + REGISTER_METHOD(MLPipelineNodeInfoSetProperty); // Pipeline API end #undef REGISTER_METHOD @@ -608,7 +614,7 @@ void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson: int res_id = -1; result = single_manager_.OpenModel(model_path, in_tensors_info, out_tensors_info, nnfw_e, hw_e, - is_dynamic_mode, &res_id); + is_dynamic_mode, &res_id); if (!result) { ReportError(result, &out); return; @@ -727,11 +733,8 @@ void MlInstance::MLPipelineGetState(const picojson::value& args, picojson::objec void MlInstance::MLPipelineStart(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); - if (!args.get(kId).is()) { - LoggerD("id is not a number"); - ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid pipeline"}, &out); - return; - } + CHECK_ARGS(args, kId, double, out); + auto id = static_cast(args.get(kId).get()); PlatformResult result = pipeline_manager_.Start(id); @@ -749,11 +752,8 @@ void MlInstance::MLPipelineStart(const picojson::value& args, picojson::object& void MlInstance::MLPipelineStop(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); - if (!args.get(kId).is()) { - LoggerD("id is not a number"); - ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid pipeline"}, &out); - return; - } + CHECK_ARGS(args, kId, double, out); + auto id = static_cast(args.get(kId).get()); PlatformResult result = pipeline_manager_.Stop(id); @@ -793,17 +793,8 @@ void MlInstance::MLPipelineDispose(const picojson::value& args, picojson::object void MlInstance::MLPipelineGetNodeInfo(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); - if (!args.get(kId).is()) { - LoggerD("id is not a number"); - ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid pipeline"}, &out); - return; - } - - if (!args.get(kName).is()) { - LoggerD("name is not a string"); - ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid name"}, &out); - return; - } + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kName, std::string, out); auto name = args.get(kName).get(); auto id = static_cast(args.get(kId).get()); @@ -891,11 +882,61 @@ void MlInstance::MLPipelineGetValve(const picojson::value& args, picojson::objec // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin +void MlInstance::MLPipelineNodeInfoGetProperty(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kNodeName, std::string, out); + CHECK_ARGS(args, kName, std::string, out); + CHECK_ARGS(args, kType, std::string, out); + + auto id = static_cast(args.get(kId).get()); + const auto& name = args.get(kName).get(); + const auto& node_name = args.get(kNodeName).get(); + const auto& type = args.get(kType).get(); + + PlatformResult result = pipeline_manager_.getProperty(id, node_name, name, type, &out); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // NodeInfo::getProperty() end // NodeInfo::setProperty() begin +void MlInstance::MLPipelineNodeInfoSetProperty(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kNodeName, std::string, out); + CHECK_ARGS(args, kName, std::string, out); + CHECK_ARGS(args, kType, std::string, out); + + auto id = static_cast(args.get(kId).get()); + const auto& name = args.get(kName).get(); + const auto& node_name = args.get(kNodeName).get(); + const auto& type = args.get(kType).get(); + + if (kBOOLEAN == type) { + CHECK_ARGS(args, kProperty, bool, out); + } else if (kSTRING == type) { + CHECK_ARGS(args, kProperty, std::string, out); + } else { + CHECK_ARGS(args, kProperty, double, out); + } + const picojson::value& property = args.get(kProperty); + + PlatformResult result = pipeline_manager_.setProperty(id, node_name, name, type, property); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 9619647..cb05d46 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -124,11 +124,11 @@ class MlInstance : public common::ParsedInstance { // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin - + void MLPipelineNodeInfoGetProperty(const picojson::value& args, picojson::object& out); // NodeInfo::getProperty() end // NodeInfo::setProperty() begin - + void MLPipelineNodeInfoSetProperty(const picojson::value& args, picojson::object& out); // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 11ec31a..fe35948 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -71,7 +71,7 @@ Pipeline::Pipeline(int id, const std::string& state_change_listener_name, ScopeLogger("id: [%d], state_change_listener_name: [%s]", id, state_change_listener_name.c_str()); } -// PipelineManager::createPipeline() begin +// Pipeline::createPipeline() begin PlatformResult Pipeline::CreatePipeline(int id, const std::string& definition, const std::string& state_change_listener_name, common::Instance* instance_ptr, @@ -107,7 +107,7 @@ PlatformResult Pipeline::CreatePipeline(int id, const std::string& definition, *out = std::move(pipeline_ptr); return PlatformResult{}; } -// PipelineManager::createPipeline() end +// Pipeline::createPipeline() end Pipeline::~Pipeline() { ScopeLogger("Destroying pipeline: [%d]", id_); @@ -295,11 +295,36 @@ PlatformResult Pipeline::GetValve(const std::string& name) { // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin +PlatformResult Pipeline::getProperty(const std::string& node_name, const std::string& name, + const std::string& type, picojson::object* property) { + ScopeLogger("id_: [%d], name: [%s], type: [%s]", id_, name.c_str(), type.c_str()); + + auto nodeinfo_it = node_info_.find(node_name); + if (node_info_.end() == nodeinfo_it) { + LoggerD("NodeInfo [%s] not found", node_name.c_str()); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"}; + } + + auto ret = nodeinfo_it->second->getProperty(name, type, property); + return ret; +} // NodeInfo::getProperty() end // NodeInfo::setProperty() begin +PlatformResult Pipeline::setProperty(const std::string& node_name, const std::string& name, + const std::string& type, const picojson::value& property) { + ScopeLogger("id_: [%d], name: [%s], type: [%s]", id_, name.c_str(), type.c_str()); + + auto nodeinfo_it = node_info_.find(node_name); + if (node_info_.end() == nodeinfo_it) { + LoggerD("NodeInfo [%s] not found", node_name.c_str()); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"}; + } + auto ret = nodeinfo_it->second->setProperty(name, type, property); + return ret; +} // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 110cec9..afe3fee 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -104,11 +104,13 @@ class Pipeline { // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin - + PlatformResult getProperty(const std::string& node_name, const std::string& name, + const std::string& type, picojson::object* property); // NodeInfo::getProperty() end // NodeInfo::setProperty() begin - + PlatformResult setProperty(const std::string& node_name, const std::string& name, + const std::string& type, const picojson::value& property); // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index a403200..3e1cc41 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -193,11 +193,37 @@ PlatformResult PipelineManager::GetValve(const std::string& name, int pipeline_i // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin +PlatformResult PipelineManager::getProperty(int id, const std::string& node_name, + const std::string& name, const std::string& type, + picojson::object* property) { + ScopeLogger("id: [%d], name [%s], nodeName [%s], type [%s] ", id, name.c_str(), node_name.c_str(), + type.c_str()); + auto pipeline_it = pipelines_.find(id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + + return pipeline_it->second->getProperty(node_name, name, type, property); +} // NodeInfo::getProperty() end // NodeInfo::setProperty() begin +PlatformResult PipelineManager::setProperty(int id, const std::string& node_name, + const std::string& name, const std::string& type, + const picojson::value& property) { + ScopeLogger("id: [%d], name [%s], nodeName [%s], type [%s] ", id, name.c_str(), node_name.c_str(), + type.c_str()); + auto pipeline_it = pipelines_.find(id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + + return pipeline_it->second->setProperty(node_name, name, type, property); +} // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 666887f..f986624 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -92,11 +92,13 @@ class PipelineManager { // Pipeline::unregisterCustomFilter() end // NodeInfo::getProperty() begin - + PlatformResult getProperty(int id, const std::string& node_name, const std::string& name, + const std::string& type, picojson::object* property); // NodeInfo::getProperty() end // NodeInfo::setProperty() begin - + PlatformResult setProperty(int id, const std::string& node_name, const std::string& name, + const std::string& type, const picojson::value& property); // NodeInfo::setProperty() end // Source::inputTensorsInfo begin diff --git a/src/ml/ml_pipeline_nodeinfo.cc b/src/ml/ml_pipeline_nodeinfo.cc index 91fe836..c6ebfbf 100644 --- a/src/ml/ml_pipeline_nodeinfo.cc +++ b/src/ml/ml_pipeline_nodeinfo.cc @@ -23,6 +23,18 @@ using common::PlatformResult; using common::ErrorCode; +namespace { +const std::string kProperty = "property"; +const std::string kBOOLEAN = "BOOLEAN"; +const std::string kDOUBLE = "DOUBLE"; +const std::string kENUM = "ENUM"; +const std::string kINT32 = "INT32"; +const std::string kUINT32 = "UINT32"; +const std::string kINT64 = "INT64"; +const std::string kUINT64 = "UINT64"; +const std::string kSTRING = "STRING"; +} // namespace + namespace extension { namespace ml { namespace pipeline { @@ -45,7 +57,7 @@ PlatformResult NodeInfo::CreateNodeInfo(ml_pipeline_h pipeline, const std::strin } NodeInfo::NodeInfo(const std::string& name) : name_{name} { - ScopeLogger("name: [%s], ", name.c_str()); + ScopeLogger("name: [%s] ", name.c_str()); } NodeInfo::~NodeInfo() { @@ -59,6 +71,174 @@ NodeInfo::~NodeInfo() { } } +PlatformResult NodeInfo::getProperty(const std::string& name, const std::string& type, + picojson::object* property) { + ScopeLogger("name: [%s], type: [%s]", name.c_str(), type.c_str()); + if (kBOOLEAN == type) { + int32_t val; + int ret = ml_pipeline_element_get_property_bool(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_bool() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty Bool %d", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kDOUBLE == type) { + double val; + int ret = ml_pipeline_element_get_property_double(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_double() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty Double %f", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kENUM == type) { + uint32_t val; + int ret = ml_pipeline_element_get_property_enum(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_enum() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty Enum %u", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kINT32 == type) { + int32_t val; + int ret = ml_pipeline_element_get_property_int32(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_int32() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty Int32 %d", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kINT64 == type) { + int64_t val; + int ret = ml_pipeline_element_get_property_int64(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_int64() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty Int64 %lld", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kUINT32 == type) { + uint32_t val; + int ret = ml_pipeline_element_get_property_uint32(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_uint32() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty UInt32 %u", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kUINT64 == type) { + uint64_t val; + int ret = ml_pipeline_element_get_property_uint64(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_uint64() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty UInt64 %llu", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else if (kSTRING == type) { + char* val; + int ret = ml_pipeline_element_get_property_string(node_info_, name.c_str(), &val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_property_string() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get property of NodeInfo"); + } + LoggerD("getProperty UString %s", val); + property->insert(std::make_pair(kProperty, picojson::value(static_cast(val)))); + } else { + return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid PropertyType", + ("Unknown property type")); + } + + return PlatformResult{}; +} + +PlatformResult NodeInfo::setProperty(const std::string& name, const std::string& type, + const picojson::value& property) { + ScopeLogger("name: [%s], type: [%s]", name.c_str(), type.c_str()); + + if (kBOOLEAN == type) { + bool bval = property.get(); + int32_t val = bval ? 1 : 0; + int ret = ml_pipeline_element_set_property_bool(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_bool() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kDOUBLE == type) { + double val = property.get(); + int ret = ml_pipeline_element_set_property_double(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_double() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kENUM == type) { + uint32_t val = static_cast(property.get()); + int ret = ml_pipeline_element_set_property_enum(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_enum() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kINT32 == type) { + int32_t val = static_cast(property.get()); + int ret = ml_pipeline_element_set_property_int32(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_int32() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kINT64 == type) { + int64_t val = static_cast(property.get()); + int ret = ml_pipeline_element_set_property_int64(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_int64() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kUINT32 == type) { + uint32_t val = static_cast(property.get()); + int ret = ml_pipeline_element_set_property_uint32(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_uint32() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kUINT64 == type) { + uint64_t val = static_cast(property.get()); + int ret = ml_pipeline_element_set_property_uint64(node_info_, name.c_str(), val); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_uint64() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else if (kSTRING == type) { + const std::string& val = property.get(); + int ret = ml_pipeline_element_set_property_string(node_info_, name.c_str(), val.c_str()); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_set_property_string() failed: [%d] (%s)", ret, + get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not set property of NodeInfo"); + } + } else { + return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid PropertyType", + ("Unknown property type")); + } + + return PlatformResult{}; +} + } // namespace pipeline } // namespace ml -} // namespace extension \ No newline at end of file +} // namespace extension diff --git a/src/ml/ml_pipeline_nodeinfo.h b/src/ml/ml_pipeline_nodeinfo.h index 4140025..dcc22ac 100644 --- a/src/ml/ml_pipeline_nodeinfo.h +++ b/src/ml/ml_pipeline_nodeinfo.h @@ -40,6 +40,11 @@ class NodeInfo { ~NodeInfo(); + PlatformResult getProperty(const std::string& name, const std::string& type, + picojson::object* property); + PlatformResult setProperty(const std::string& name, const std::string& type, + const picojson::value& property); + private: NodeInfo(const std::string& name); const std::string name_; @@ -50,4 +55,4 @@ class NodeInfo { } // namespace ml } // namespace extension -#endif // ML_ML_PIPELINE_NODEINFO_H_ \ No newline at end of file +#endif // ML_ML_PIPELINE_NODEINFO_H_ -- 2.7.4 From e98e2726c53ff6a5f054159214b7c78ac8ff44fc Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Wed, 20 Jan 2021 11:28:50 +0100 Subject: [PATCH 13/16] [ML][Common] Add TensorsInfo.getTensorsData and TensorsData ACR: TWDAPI-273 Test code: var ti = new tizen.ml.TensorsInfo(); ti.addTensorInfo("tensor1", "UINT8", [1, 1]) ti.addTensorInfo("tensor2", "UINT8", [2, 4]) var td = ti.getTensorsData(); console.log(td.count) Verification: Built successful. Tested in Chrome Dev console. Change-Id: Id480d20c1a32d03113c6dbc73cbd81938a98931f Signed-off-by: Rafal Walczyna --- src/ml/js/ml_common.js | 29 +++++++++-- src/ml/ml.gyp | 3 ++ src/ml/ml_instance.cc | 37 ++++++++++++- src/ml/ml_instance.h | 4 ++ src/ml/ml_tensors_data_manager.cc | 106 ++++++++++++++++++++++++++++++++++++++ src/ml/ml_tensors_data_manager.h | 73 ++++++++++++++++++++++++++ src/ml/ml_tensors_info_manager.cc | 16 +++++- src/ml/ml_tensors_info_manager.h | 6 ++- 8 files changed, 266 insertions(+), 8 deletions(-) create mode 100644 src/ml/ml_tensors_data_manager.cc create mode 100644 src/ml/ml_tensors_data_manager.h diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 62be9ff..8d8d19c 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -65,19 +65,25 @@ var TensorType = { // TensorsData -var TensorsData = function() { +var TensorsData = function(id, tensorsInfoId) { Object.defineProperties(this, { count: { enumerable: true, get: function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + return this._tensorsInfo.count; } }, tensorsInfo: { enumerable: true, get: function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + return this._tensorsInfo.clone(); } + }, + _id: { value: id, writable: false, enumerable: false }, + _tensorsInfo: { + value: new TensorsInfo(tensorsInfoId), + writable: false, + enumerable: false } }); }; @@ -511,9 +517,24 @@ TensorsInfo.prototype.getTensorSize = function() { return native_.getResultObject(result); }; +var TensorsInfoGetTensorsDataValidExceptions = ['AbortError', 'NotSupportedError']; + TensorsInfo.prototype.getTensorsData = function() { _CheckIfTensorsInfoNotDisposed(this._id); - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var callArgs = { + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoGetTensorsData', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGetTensorsDataValidExceptions, + AbortError + ); + } + return new TensorsData(result.tensorsDataId, result.tensorsInfoId); }; TensorsInfo.prototype.dispose = function() { diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index cd692f1..40aebd3 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -24,8 +24,11 @@ 'ml_pipeline_switch.cc', 'ml_pipeline_switch.h', #TODO pipeline Source + #TODO pipeline Valve 'ml_pipeline_valve.h', 'ml_pipeline_valve.cc', + 'ml_tensors_data_manager.cc', + 'ml_tensors_data_manager.h', 'ml_tensors_info_manager.cc', 'ml_tensors_info_manager.h', 'ml_single_manager.cc', diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 9fe0111..bb6a0e0 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -30,6 +30,7 @@ namespace { const std::string kNnfw = "nnfw"; const std::string kHw = "hw"; const std::string kTensorsInfoId = "tensorsInfoId"; +const std::string kTensorsDataId = "tensorsDataId"; const std::string kIndex = "index"; const std::string kType = "type"; const std::string kName = "name"; @@ -68,7 +69,10 @@ using namespace common; CHECK_EXIST(args, name, out) \ CHECK_TYPE(args, name, type, out) -MlInstance::MlInstance() : single_manager_{&tensors_info_manager_}, pipeline_manager_{this} { +MlInstance::MlInstance() + : tensors_info_manager_{&tensors_data_manager_}, + single_manager_{&tensors_info_manager_}, + pipeline_manager_{this} { ScopeLogger(); using namespace std::placeholders; @@ -86,6 +90,7 @@ MlInstance::MlInstance() : single_manager_{&tensors_info_manager_}, pipeline_man REGISTER_METHOD(MLTensorsInfoGetTensorSize); REGISTER_METHOD(MLTensorsInfoGetTensorType); REGISTER_METHOD(MLTensorsInfoSetTensorType); + REGISTER_METHOD(MLTensorsInfoGetTensorsData); REGISTER_METHOD(MLTensorsInfoClone); REGISTER_METHOD(MLTensorsInfoEquals); REGISTER_METHOD(MLTensorsInfoDispose); @@ -128,6 +133,10 @@ TensorsInfoManager& MlInstance::GetTensorsInfoManager() { return tensors_info_manager_; } +TensorsDataManager& MlInstance::GetTensorsDataManager() { + return tensors_data_manager_; +} + // Common ML API begin void MlInstance::MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); @@ -474,6 +483,30 @@ void MlInstance::MLTensorsInfoSetTensorType(const picojson::value& args, picojso ReportSuccess(out); } +void MlInstance::MLTensorsInfoGetTensorsData(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + + TensorsData* tensorsData = GetTensorsInfoManager().CreateTensorsData(tensorsInfo); + if (!tensorsData) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not create TensorsData")); + return; + } + + out[kTensorsDataId] = picojson::value(static_cast(tensorsData->Id())); + out[kTensorsInfoId] = picojson::value(static_cast(tensorsData->TensorsInfoId())); + ReportSuccess(out); +} + void MlInstance::MLTensorsInfoClone(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); CHECK_ARGS(args, kTensorsInfoId, double, out); @@ -608,7 +641,7 @@ void MlInstance::MLSingleManagerOpenModel(const picojson::value& args, picojson: int res_id = -1; result = single_manager_.OpenModel(model_path, in_tensors_info, out_tensors_info, nnfw_e, hw_e, - is_dynamic_mode, &res_id); + is_dynamic_mode, &res_id); if (!result) { ReportError(result, &out); return; diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 9619647..f626751 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -24,6 +24,7 @@ #include "nnstreamer/nnstreamer-single.h" #include "nnstreamer/nnstreamer.h" +#include "ml_tensors_data_manager.h" #include "ml_tensors_info_manager.h" namespace extension { @@ -34,6 +35,7 @@ class MlInstance : public common::ParsedInstance { MlInstance(); virtual ~MlInstance(); TensorsInfoManager& GetTensorsInfoManager(); + TensorsDataManager& GetTensorsDataManager(); private: // Common ML API begin @@ -48,10 +50,12 @@ class MlInstance : public common::ParsedInstance { void MLTensorsInfoGetTensorSize(const picojson::value& args, picojson::object& out); void MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out); void MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out); + void MLTensorsInfoGetTensorsData(const picojson::value& args, picojson::object& out); void MLTensorsInfoClone(const picojson::value& args, picojson::object& out); void MLTensorsInfoEquals(const picojson::value& args, picojson::object& out); void MLTensorsInfoDispose(const picojson::value& args, picojson::object& out); TensorsInfoManager tensors_info_manager_; + TensorsDataManager tensors_data_manager_; // Common ML API end // Single API begin diff --git a/src/ml/ml_tensors_data_manager.cc b/src/ml/ml_tensors_data_manager.cc new file mode 100644 index 0000000..e3d2439 --- /dev/null +++ b/src/ml/ml_tensors_data_manager.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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. + */ + +#include "ml_tensors_data_manager.h" +#include "ml_tensors_info_manager.h" + +using common::ErrorCode; +using common::PlatformResult; + +namespace extension { +namespace ml { + +TensorsData::TensorsData(ml_tensors_data_h handle, int id, TensorsInfo* tensors_info) + : handle_(handle), id_(id), tensors_info_(tensors_info) { + ScopeLogger(); +} + +TensorsData::~TensorsData() { + ScopeLogger(); + if (this->NativeDestroy()) { + LoggerE("TensorsData NativeDestroy failed"); + } + // TensorsDataManager releases tensors_info_ +} + +ml_tensors_data_h TensorsData::Handle() { + return this->handle_; +} + +int TensorsData::Id() { + return this->id_; +} + +int TensorsData::TensorsInfoId() { + return this->tensors_info_->Id(); +} + +int TensorsData::Count() { + return tensors_info_->Count(); +} + +PlatformResult TensorsData::NativeDestroy() { + ScopeLogger("id_: %d", id_); + int ret = ml_tensors_data_destroy(handle_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_data_destroy failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to destroy handle"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +TensorsDataManager::TensorsDataManager() : nextId_(0) { + ScopeLogger(); +} + +TensorsDataManager::~TensorsDataManager() { + ScopeLogger(); + map_.clear(); +}; + +TensorsData* TensorsDataManager::CreateTensorsData(TensorsInfo* tensors_info) { + ScopeLogger(); + if (nullptr == tensors_info) { + LoggerE("Could not find tensor"); + return nullptr; + } + + ml_tensors_data_h tensors_data_handle; + int ret = ml_tensors_data_create(tensors_info->Handle(), &tensors_data_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_data_create failed: %d (%s)", ret, get_error_message(ret)); + return nullptr; + } + + int id = nextId_++; + auto t = std::make_unique(tensors_data_handle, id, tensors_info); + map_[id] = std::move(t); + + return map_[id].get(); +}; + +TensorsData* TensorsDataManager::GetTensorsData(int id) { + ScopeLogger("id: %d", id); + + if (map_.end() != map_.find(id)) { + return map_[id].get(); + } + + return nullptr; +} + +} // ml +} // extension diff --git a/src/ml/ml_tensors_data_manager.h b/src/ml/ml_tensors_data_manager.h new file mode 100644 index 0000000..012a2c3 --- /dev/null +++ b/src/ml/ml_tensors_data_manager.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 __ML_TENSORS_DATA_MANAGER_H__ +#define __ML_TENSORS_DATA_MANAGER_H__ + +#include + +#include "common/logger.h" +#include "common/platform_result.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { + +class TensorsInfo; + +class TensorsData { + public: + TensorsData(ml_tensors_data_h handle, int id, TensorsInfo* tensors_info); + ~TensorsData(); + + ml_tensors_data_h Handle(); + int Id(); + int TensorsInfoId(); + int Count(); + + PlatformResult NativeDestroy(); + + private: + TensorsData(TensorsData const&) = delete; + TensorsData& operator=(TensorsData const&) = delete; + + ml_tensors_data_h handle_; + int id_; + TensorsInfo* tensors_info_; +}; + +class TensorsDataManager { + public: + TensorsDataManager(); + ~TensorsDataManager(); + + TensorsData* CreateTensorsData(TensorsInfo* tensors_info); + TensorsData* GetTensorsData(int id); + + private: + TensorsDataManager(TensorsDataManager const&) = delete; + TensorsDataManager& operator=(TensorsDataManager const&) = delete; + + std::unordered_map> map_; + int nextId_; +}; + +} // ml +} // extension +#endif // __ML_TENSORS_DATA_MANAGER_H__ diff --git a/src/ml/ml_tensors_info_manager.cc b/src/ml/ml_tensors_info_manager.cc index 8947aa6..9a052df 100644 --- a/src/ml/ml_tensors_info_manager.cc +++ b/src/ml/ml_tensors_info_manager.cc @@ -280,7 +280,8 @@ PlatformResult TensorsInfo::NativeGetTensorSize(int index, size_t* size) { return PlatformResult(ErrorCode::NO_ERROR); } -TensorsInfoManager::TensorsInfoManager() : nextId_(0) { +TensorsInfoManager::TensorsInfoManager(TensorsDataManager* tensors_data_manager) + : nextId_(0), tensors_data_manager_(tensors_data_manager) { ScopeLogger(); } @@ -388,5 +389,18 @@ PlatformResult TensorsInfoManager::DisposeTensorsInfo(TensorsInfo* t) { return PlatformResult(ErrorCode::NO_ERROR); } +TensorsData* TensorsInfoManager::CreateTensorsData(TensorsInfo* tensors_info) { + ScopeLogger(); + if (nullptr == tensors_info) { + LoggerE("Could not find tensor"); + return nullptr; + } + // create clone of tensors_info, this clone has to be disposed + // on TensorsData disposal + TensorsInfo* t_info = CloneTensorsInfo(tensors_info); + + return tensors_data_manager_->CreateTensorsData(t_info); +}; + } // ml } // extension diff --git a/src/ml/ml_tensors_info_manager.h b/src/ml/ml_tensors_info_manager.h index 6320216..56f1c1d 100644 --- a/src/ml/ml_tensors_info_manager.h +++ b/src/ml/ml_tensors_info_manager.h @@ -22,6 +22,7 @@ #include "common/logger.h" #include "common/platform_result.h" +#include "ml_tensors_data_manager.h" #include "ml_utils.h" #include @@ -66,7 +67,7 @@ class TensorsInfo { class TensorsInfoManager { public: - TensorsInfoManager(); + TensorsInfoManager(TensorsDataManager* tensors_data_manager); ~TensorsInfoManager(); TensorsInfo* CreateTensorsInfo(); // handle will be destroyed on TensorsInfo object destruction @@ -79,12 +80,15 @@ class TensorsInfoManager { PlatformResult DisposeTensorsInfo(ml_tensors_info_h handle); PlatformResult DisposeTensorsInfo(TensorsInfo* t); + TensorsData* CreateTensorsData(TensorsInfo* tensors_info); + private: TensorsInfoManager(TensorsInfoManager const&) = delete; TensorsInfoManager& operator=(TensorsInfoManager const&) = delete; std::map> map_by_id_; std::map> map_by_handle_; int nextId_; + TensorsDataManager* tensors_data_manager_; }; } // ml -- 2.7.4 From c37652863fb118f24a3dfac3fdd72a0b3dcd992c Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Wed, 20 Jan 2021 14:19:15 +0100 Subject: [PATCH 14/16] [ML][Common] Add TensorsData.dispose method ACR: TWDAPI-273 Test code: var ti = new tizen.ml.TensorsInfo(); ti.addTensorInfo("tensor1", "UINT8", [1, 1]) ti.addTensorInfo("tensor2", "UINT8", [2, 4]) var td = ti.getTensorsData(); console.log(td.count) td.dispose(); console.log(td.count) [Verification] Built successful. Tested in Chrome Dev console. Change-Id: I9997467b36908d6e031473e58e2b3defbf253e00 Signed-off-by: Rafal Walczyna --- src/ml/js/ml_common.js | 29 ++++++++++++++++++++++++++++- src/ml/ml_instance.cc | 28 ++++++++++++++++++++++++++++ src/ml/ml_instance.h | 3 +++ src/ml/ml_tensors_data_manager.cc | 21 +++++++++++++++++++++ src/ml/ml_tensors_data_manager.h | 3 +++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 8d8d19c..1c11756 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -65,6 +65,14 @@ var TensorType = { // TensorsData +var _ValidTensorsDataIds = new Set(); + +function _CheckIfTensorsDataNotDisposed(id) { + if (false == _ValidTensorsDataIds.has(id)) { + throw new WebAPIException(WebAPIException.ABORT_ERR, 'TensorsData is disposed'); + } +} + var TensorsData = function(id, tensorsInfoId) { Object.defineProperties(this, { count: { @@ -76,6 +84,7 @@ var TensorsData = function(id, tensorsInfoId) { tensorsInfo: { enumerable: true, get: function() { + _CheckIfTensorsDataNotDisposed(this._id); return this._tensorsInfo.clone(); } }, @@ -86,18 +95,36 @@ var TensorsData = function(id, tensorsInfoId) { enumerable: false } }); + _ValidTensorsDataIds.add(id); }; TensorsData.prototype.getTensorRawData = function() { + _CheckIfTensorsDataNotDisposed(); throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); }; TensorsData.prototype.setTensorData = function() { + _CheckIfTensorsDataNotDisposed(); throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); }; TensorsData.prototype.dispose = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + if (false == _ValidTensorsDataIds.has(this._id)) { + privUtils_.log('TensorsData already disposed'); + return; + } + var callArgs = { + tensorsDataId: this._id + }; + + var result = native_.callSync('MLTensorsDataDispose', callArgs); + + if (native_.isFailure(result)) { + return; + } + _ValidTensorsDataIds['delete'](this._id); + // underlying tensorsInfo_ is also invalid + _ValidTensorsInfoIds['delete'](this._tensorsInfo._id); }; // TensorsInfo diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index bb6a0e0..a60a0f0 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -95,6 +95,8 @@ MlInstance::MlInstance() REGISTER_METHOD(MLTensorsInfoEquals); REGISTER_METHOD(MLTensorsInfoDispose); + REGISTER_METHOD(MLTensorsDataDispose); + // Single API begin REGISTER_METHOD(MLSingleManagerOpenModel); // MachineLearningSingle::openModelAsync() @@ -568,6 +570,32 @@ void MlInstance::MLTensorsInfoDispose(const picojson::value& args, picojson::obj } ReportSuccess(out); } + +void MlInstance::MLTensorsDataDispose(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsDataId, double, out); + int tensors_data_id = static_cast(args.get(kTensorsDataId).get()); + + TensorsData* tensors_data = GetTensorsDataManager().GetTensorsData(tensors_data_id); + if (nullptr == tensors_data) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsData error"), &out, + ("Could not find TensorsData handle with given id: %d", tensors_data_id)); + return; + } + // Dispose underlying tensorsInfo + PlatformResult result = GetTensorsInfoManager().DisposeTensorsInfo(tensors_data->TensorsInfoId()); + if (!result) { + LogAndReportError(result, &out); + return; + } + + result = GetTensorsDataManager().DisposeTensorsData(tensors_data_id); + if (!result) { + LogAndReportError(result, &out); + return; + } + ReportSuccess(out); +} // Common ML API end // Single API begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index f626751..499e89a 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -54,6 +54,9 @@ class MlInstance : public common::ParsedInstance { void MLTensorsInfoClone(const picojson::value& args, picojson::object& out); void MLTensorsInfoEquals(const picojson::value& args, picojson::object& out); void MLTensorsInfoDispose(const picojson::value& args, picojson::object& out); + + void MLTensorsDataDispose(const picojson::value& args, picojson::object& out); + TensorsInfoManager tensors_info_manager_; TensorsDataManager tensors_data_manager_; // Common ML API end diff --git a/src/ml/ml_tensors_data_manager.cc b/src/ml/ml_tensors_data_manager.cc index e3d2439..225e289 100644 --- a/src/ml/ml_tensors_data_manager.cc +++ b/src/ml/ml_tensors_data_manager.cc @@ -102,5 +102,26 @@ TensorsData* TensorsDataManager::GetTensorsData(int id) { return nullptr; } +PlatformResult TensorsDataManager::DisposeTensorsData(int id) { + ScopeLogger("id: %d", id); + + TensorsData* t = GetTensorsData(id); + + return DisposeTensorsData(t); +} + +PlatformResult TensorsDataManager::DisposeTensorsData(TensorsData* t) { + ScopeLogger(); + + if (nullptr == t) { + LoggerE("Could not find tensor"); + return PlatformResult(ErrorCode::ABORT_ERR); + } + + map_.erase(t->Id()); + + return PlatformResult(ErrorCode::NO_ERROR); +} + } // ml } // extension diff --git a/src/ml/ml_tensors_data_manager.h b/src/ml/ml_tensors_data_manager.h index 012a2c3..39811df 100644 --- a/src/ml/ml_tensors_data_manager.h +++ b/src/ml/ml_tensors_data_manager.h @@ -60,6 +60,9 @@ class TensorsDataManager { TensorsData* CreateTensorsData(TensorsInfo* tensors_info); TensorsData* GetTensorsData(int id); + PlatformResult DisposeTensorsData(int id); + PlatformResult DisposeTensorsData(TensorsData* t); + private: TensorsDataManager(TensorsDataManager const&) = delete; TensorsDataManager& operator=(TensorsDataManager const&) = delete; -- 2.7.4 From eac9c6193b2e59706f7c03cefb87d667b4f6f677 Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Mon, 25 Jan 2021 14:14:43 +0100 Subject: [PATCH 15/16] [ML][Single] Implemented SingleShot.input member - set MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * added set feature for SingleShot.input * added single gathering of SingleShot.input and output (wihout checking native layer every time) [ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-273 [Verification] Code compiles without errors. Checked in Chrome console: var model = tizen.ml.single.openModel("documents/mobilenet_v1_1.0_224_quant.tflite") model.input > TensorsInfo {_previouslyConstructed: true, _id: 1} var newTI = new tizen.ml.TensorsInfo() newTI.addTensorInfo("input", "UINT8", [3,224,224,1]) model.input = newTI; model.input > TensorsInfo {_previouslyConstructed: true, _id: 2} /// calling getter multiple times return always the same TensorsInfo Change-Id: I16c33a0ba515aba1efe2f5d93d0d3225b410aced --- src/ml/js/ml_single.js | 66 +++++++++++++++++++++++++++++++-------------- src/ml/ml_instance.cc | 25 +++++++++++++++++ src/ml/ml_instance.h | 1 + src/ml/ml_single_manager.cc | 19 +++++++++++++ src/ml/ml_single_manager.h | 1 + src/ml/ml_singleshot.cc | 11 ++++++++ src/ml/ml_singleshot.h | 2 +- 7 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index 40a00de..2fdf571 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -99,13 +99,41 @@ MachineLearningSingle.prototype.openModel = function() { // SingleShot interface (input & output) var ValidInputExceptions = ['TypeMismatchError', 'AbortError']; var SingleShot = function(id) { + var _input, _output; Object.defineProperties(this, { input: { get: function() { - var result = native_.callSync('MLSingleShotGetTensorsInfo', { + if (!_input) { + var result = native_.callSync('MLSingleShotGetTensorsInfo', { + id: this._id, + getInputMode: true // true means gathering input information + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInputExceptions, + AbortError + ); + } + _input = new TensorsInfo(result.id); + } + return _input; + }, + set: function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'inTensorsInfo', + type: types_.PLATFORM_OBJECT, + values: TensorsInfo + } + ]); + + var nativeArgs = { id: this._id, - getInputMode: true // true means gathering input information - }); + inTensorsInfo: args.inTensorsInfo._id + }; + + var result = native_.callSync('MLSingleShotSetInputInfo', nativeArgs); if (native_.isFailure(result)) { throw native_.getErrorObjectAndValidate( result, @@ -113,28 +141,26 @@ var SingleShot = function(id) { AbortError ); } - - return new TensorsInfo(result.id); - }, - set: function(v) { - /* TODO*/ + _input = args.inTensorsInfo; } }, output: { get: function() { - var result = native_.callSync('MLSingleShotGetTensorsInfo', { - id: this._id, - getInputMode: false // false means gathering output information - }); - if (native_.isFailure(result)) { - throw native_.getErrorObjectAndValidate( - result, - ValidInputExceptions, - AbortError - ); + if (!_output) { + var result = native_.callSync('MLSingleShotGetTensorsInfo', { + id: this._id, + getInputMode: false // false means gathering output information + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInputExceptions, + AbortError + ); + } + _output = new TensorsInfo(result.id); } - - return new TensorsInfo(result.id); + return _output.clone(); // return new copy to make it 'readonly' }, set: function(v) { /* readonly */ diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index f9fc868..e4c7833 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -106,6 +106,7 @@ MlInstance::MlInstance() // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback REGISTER_METHOD(MLSingleShotGetTensorsInfo); + REGISTER_METHOD(MLSingleShotSetInputInfo); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() @@ -713,6 +714,30 @@ void MlInstance::MLSingleShotGetTensorsInfo(const picojson::value& args, picojso ReportSuccess(out); } +void MlInstance::MLSingleShotSetInputInfo(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kInTensorsInfo, double, out); + + auto id = static_cast(args.get(kId).get()); + auto inTensorId = static_cast(args.get(kInTensorsInfo).get()); + + TensorsInfo* in_tensors_info = GetTensorsInfoManager().GetTensorsInfo(inTensorId); + if (nullptr == in_tensors_info) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", inTensorId)); + return; + } + + auto ret = single_manager_.SetNativeInputInfo(id, in_tensors_info); + if (!ret) { + ReportError(ret, &out); + return; + } + + ReportSuccess(out); +} + // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 5e9dd63..95125fb 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -67,6 +67,7 @@ class MlInstance : public common::ParsedInstance { // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback void MLSingleShotGetTensorsInfo(const picojson::value& args, picojson::object& out); + void MLSingleShotSetInputInfo(const picojson::value& args, picojson::object& out); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_single_manager.cc b/src/ml/ml_single_manager.cc index 4bc3d1a..5f7438d 100644 --- a/src/ml/ml_single_manager.cc +++ b/src/ml/ml_single_manager.cc @@ -87,6 +87,25 @@ PlatformResult SingleManager::GetNativeTensorsInfo(int id, bool get_input_mode, return PlatformResult{}; } +PlatformResult SingleManager::SetNativeInputInfo(int id, TensorsInfo* inTensorsInfo) { + ScopeLogger(); + + SingleShot* single = GetSingleShot(id); + if (!single) { + LoggerE("Could not find singleShot handle"); + return PlatformResult(ErrorCode::ABORT_ERR); + } + + ml_tensors_info_h in_info = inTensorsInfo ? inTensorsInfo->Handle() : nullptr; + + PlatformResult ret = single->SetInputInfo(in_info); + if (!ret) { + return ret; + } + + return PlatformResult{}; +} + // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_single_manager.h b/src/ml/ml_single_manager.h index bf98373..2edbb8e 100644 --- a/src/ml/ml_single_manager.h +++ b/src/ml/ml_single_manager.h @@ -44,6 +44,7 @@ class SingleManager { // MachineLearningSingle::openModelAsync() // OpenModelSuccessCallback PlatformResult GetNativeTensorsInfo(int id, bool get_input_mode, int* res_id); + PlatformResult SetNativeInputInfo(int id, TensorsInfo* inTensorsInfo); // SingleShot::invoke() // SingleShot::getValue() // SingleShot::setValue() diff --git a/src/ml/ml_singleshot.cc b/src/ml/ml_singleshot.cc index beff9f1..9a4c96c 100644 --- a/src/ml/ml_singleshot.cc +++ b/src/ml/ml_singleshot.cc @@ -63,6 +63,17 @@ PlatformResult SingleShot::GetTensorsInfo(bool get_input_mode, ml_tensors_info_h return PlatformResult{}; } +PlatformResult SingleShot::SetInputInfo(ml_tensors_info_h in_info) { + ScopeLogger(); + int ret = ml_single_set_input_info(handle_, in_info); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_single_set_input_info failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to set input info"); + } + + return PlatformResult{}; +} + // SingleShot::invoke() // SingleShot::getValue() diff --git a/src/ml/ml_singleshot.h b/src/ml/ml_singleshot.h index a78d955..35c18b4 100644 --- a/src/ml/ml_singleshot.h +++ b/src/ml/ml_singleshot.h @@ -42,7 +42,7 @@ class SingleShot { ~SingleShot(); PlatformResult GetTensorsInfo(bool get_input_mode, ml_tensors_info_h* result); - + PlatformResult SetInputInfo(ml_tensors_info_h in_info); // SingleShot::invoke() // SingleShot::getValue() -- 2.7.4 From 353eeed6c663a1bedbe819e2a9ae0405c72258ed Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Tue, 26 Jan 2021 13:56:06 +0100 Subject: [PATCH 16/16] [ML][Pipeline] GetSource implementation ACR: TWDAPI-274 [Verification] Code compiles without error. Tested in chrome console. var pipeline = tizen.ml.pipeline.createPipeline("appsrc name=appsrc ! other/tensor,dimension=(string)4:1:1:1, type=(string)uint8,framerate=(fraction)0/1 ! tensor_if name=tif compared-value=CUSTOM compared-value-option=tif_custom_cb_name ") var source = pipeline.getSource("appsrc") var tensor = source.inputTensorsInfo Change-Id: I3c09d2f91758c19e82ade9e6e5237ddc0a8ef76e Signed-off-by: Lukasz Bardeli --- src/ml/js/ml_pipeline.js | 68 ++++++++++++++++++++++++++++++++++ src/ml/ml.gyp | 4 +- src/ml/ml_instance.cc | 38 ++++++++++++++++++- src/ml/ml_instance.h | 4 +- src/ml/ml_pipeline.cc | 34 ++++++++++++++--- src/ml/ml_pipeline.h | 6 ++- src/ml/ml_pipeline_manager.cc | 31 +++++++++++++++- src/ml/ml_pipeline_manager.h | 8 ++-- src/ml/ml_pipeline_source.cc | 86 +++++++++++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline_source.h | 55 +++++++++++++++++++++++++++ 10 files changed, 318 insertions(+), 16 deletions(-) create mode 100644 src/ml/ml_pipeline_source.cc create mode 100644 src/ml/ml_pipeline_source.h diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index 425e34c..16a18c9 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -208,7 +208,75 @@ Pipeline.prototype.getNodeInfo = function() { //Pipeline::getNodeInfo() end //Pipeline::getSource() begin +var ValidInputTensorsInfoExceptions = ['NotFoundError', 'AbortError']; +function Source(name, pipeline_id) { + Object.defineProperties(this, { + name: { + enumerable: true, + value: name + }, + inputTensorsInfo: { + get: function() { + var result = native_.callSync('MLPipelineGetInputTensorsInfo', { + id: this._pipeline_id, + name: this.name + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInputTensorsInfoExceptions, + AbortError + ); + } + return new TensorsInfo(result.id); + } + }, + _pipeline_id: { + value: pipeline_id + } + }); +} + +var ValidPipelineGetSourceExceptions = [ + 'InvalidStateError', + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; + +Pipeline.prototype.getSource = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + } + ]); + + if (!args.has.name) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: name is mandatory' + ); + } + + var nativeArgs = { + id: this._id, + name: args.name + }; + + var result = native_.callSync('MLPipelineGetSource', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineGetSourceExceptions, + AbortError + ); + } + + return new Source(args.name, this._id); +}; //Pipeline::getSource() end //Pipeline::getSwitch() begin diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index 40aebd3..0b08553 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -23,8 +23,8 @@ 'ml_pipeline_nodeinfo.h', 'ml_pipeline_switch.cc', 'ml_pipeline_switch.h', - #TODO pipeline Source - #TODO pipeline Valve + 'ml_pipeline_source.h', + 'ml_pipeline_source.cc', 'ml_pipeline_valve.h', 'ml_pipeline_valve.cc', 'ml_tensors_data_manager.cc', diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index e4c7833..72bef27 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -76,7 +76,7 @@ using namespace common; MlInstance::MlInstance() : tensors_info_manager_{&tensors_data_manager_}, single_manager_{&tensors_info_manager_}, - pipeline_manager_{this} { + pipeline_manager_{this, &tensors_info_manager_} { ScopeLogger(); using namespace std::placeholders; @@ -128,6 +128,8 @@ MlInstance::MlInstance() REGISTER_METHOD(MLPipelineGetValve); REGISTER_METHOD(MLPipelineNodeInfoGetProperty); REGISTER_METHOD(MLPipelineNodeInfoSetProperty); + REGISTER_METHOD(MLPipelineGetSource); + REGISTER_METHOD(MLPipelineGetInputTensorsInfo); // Pipeline API end #undef REGISTER_METHOD @@ -901,7 +903,24 @@ void MlInstance::MLPipelineGetNodeInfo(const picojson::value& args, picojson::ob // Pipeline::getNodeInfo() end // Pipeline::getSource() begin +void MlInstance::MLPipelineGetSource(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kName, std::string, out); + + auto name = args.get(kName).get(); + auto id = static_cast(args.get(kId).get()); + + PlatformResult result = pipeline_manager_.GetSource(id, name); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -1030,7 +1049,24 @@ void MlInstance::MLPipelineNodeInfoSetProperty(const picojson::value& args, pico // NodeInfo::setProperty() end // Source::inputTensorsInfo begin +void MlInstance::MLPipelineGetInputTensorsInfo(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: [%s]", args.serialize().c_str()); + + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kName, std::string, out); + auto id = static_cast(args.get(kId).get()); + const auto& name = args.get(kName).get(); + + int res_id = -1; + PlatformResult result = pipeline_manager_.getInputTensorsInfo(id, name, &res_id); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Source::inputTensorsInfo end // Source::inputData() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 95125fb..f062257 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -103,7 +103,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::getNodeInfo() end // Pipeline::getSource() begin - + void MLPipelineGetSource(const picojson::value& args, picojson::object& out); // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -139,7 +139,7 @@ class MlInstance : public common::ParsedInstance { // NodeInfo::setProperty() end // Source::inputTensorsInfo begin - + void MLPipelineGetInputTensorsInfo(const picojson::value& args, picojson::object& out); // Source::inputTensorsInfo end // Source::inputData() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index fe35948..c7e868d 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -196,6 +196,8 @@ PlatformResult Pipeline::Dispose() { valves_.clear(); + sources_.clear(); + auto ret = ml_pipeline_destroy(pipeline_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); @@ -233,7 +235,22 @@ PlatformResult Pipeline::GetNodeInfo(std::string& name) { // Pipeline::getNodeInfo() end // Pipeline::getSource() begin +PlatformResult Pipeline::GetSource(const std::string& name) { + ScopeLogger("id: [%d], name: [%s]", id_, name.c_str()); + + auto source_it = sources_.find(name); + if (sources_.end() != source_it) { + LoggerD("Source [%s] found", name.c_str()); + return PlatformResult{}; + } + std::unique_ptr source_ptr; + auto ret = Source::CreateSource(name, pipeline_, &source_ptr); + if (ret) { + sources_.insert({name, std::move(source_ptr)}); + } + return ret; +} // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -305,9 +322,7 @@ PlatformResult Pipeline::getProperty(const std::string& node_name, const std::st return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"}; } - auto ret = nodeinfo_it->second->getProperty(name, type, property); - - return ret; + return nodeinfo_it->second->getProperty(name, type, property); } // NodeInfo::getProperty() end @@ -322,13 +337,22 @@ PlatformResult Pipeline::setProperty(const std::string& node_name, const std::st return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"}; } - auto ret = nodeinfo_it->second->setProperty(name, type, property); - return ret; + return nodeinfo_it->second->setProperty(name, type, property); } // NodeInfo::setProperty() end // Source::inputTensorsInfo begin +PlatformResult Pipeline::getInputTensorsInfo(const std::string& name, ml_tensors_info_h* result) { + ScopeLogger(); + auto source_it = sources_.find(name); + if (sources_.end() == source_it) { + LoggerD("Source [%s] not found", name.c_str()); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Source not found"}; + } + + return source_it->second->getInputTensorsInfo(result); +} // Source::inputTensorsInfo end // Source::inputData() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index afe3fee..59df311 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -27,6 +27,7 @@ #include "common/picojson.h" #include "common/platform_result.h" #include "ml_pipeline_nodeinfo.h" +#include "ml_pipeline_source.h" #include "ml_pipeline_switch.h" #include "ml_pipeline_valve.h" @@ -76,7 +77,7 @@ class Pipeline { // Pipeline::getNodeInfo() end // Pipeline::getSource() begin - + PlatformResult GetSource(const std::string& name); // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -114,7 +115,7 @@ class Pipeline { // NodeInfo::setProperty() end // Source::inputTensorsInfo begin - + PlatformResult getInputTensorsInfo(const std::string& name, ml_tensors_info_h* result); // Source::inputTensorsInfo end // Source::inputData() begin @@ -152,6 +153,7 @@ class Pipeline { std::unordered_map> switches_; std::map> node_info_; std::unordered_map> valves_; + std::map> sources_; static void PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data); }; diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index 3e1cc41..364426f 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -26,7 +26,9 @@ using common::tools::ReportSuccess; namespace extension { namespace ml { -PipelineManager::PipelineManager(common::Instance* instance_ptr) : instance_ptr_{instance_ptr} { +PipelineManager::PipelineManager(common::Instance* instance_ptr, + TensorsInfoManager* tensors_info_manager) + : instance_ptr_{instance_ptr}, tensors_info_manager_{tensors_info_manager} { ScopeLogger(); } @@ -144,7 +146,17 @@ PlatformResult PipelineManager::GetNodeInfo(int id, std::string& name) { // Pipeline::getNodeInfo() end // Pipeline::getSource() begin +PlatformResult PipelineManager::GetSource(int pipeline_id, const std::string& name) { + ScopeLogger("name: [%s], pipeline_id: [%d]", name.c_str(), pipeline_id); + + auto pipeline_it = pipelines_.find(pipeline_id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", pipeline_id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + return pipeline_it->second->GetSource(name); +} // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -227,7 +239,24 @@ PlatformResult PipelineManager::setProperty(int id, const std::string& node_name // NodeInfo::setProperty() end // Source::inputTensorsInfo begin +PlatformResult PipelineManager::getInputTensorsInfo(int id, const std::string& name, int* res_id) { + ScopeLogger(); + + auto pipeline_it = pipelines_.find(id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + ml_tensors_info_h in_info = nullptr; + PlatformResult ret = pipeline_it->second->getInputTensorsInfo(name, &in_info); + if (!ret) { + return ret; + } + auto tensor_info = tensors_info_manager_->CreateTensorsInfo(in_info); + *res_id = tensor_info->Id(); + return PlatformResult{}; +} // Source::inputTensorsInfo end // Source::inputData() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index f986624..6e363dd 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -22,6 +22,7 @@ #include "common/platform_result.h" #include "ml_pipeline.h" +#include "ml_tensors_info_manager.h" using common::PlatformResult; @@ -30,7 +31,7 @@ namespace ml { class PipelineManager { public: - PipelineManager(common::Instance* instance_ptr); + PipelineManager(common::Instance* instance_ptr, TensorsInfoManager* tim); ~PipelineManager(); @@ -64,7 +65,7 @@ class PipelineManager { // Pipeline::getNodeInfo() end // Pipeline::getSource() begin - + PlatformResult GetSource(int pipeline_id, const std::string& name); // Pipeline::getSource() end // Pipeline::getSwitch() begin @@ -102,7 +103,7 @@ class PipelineManager { // NodeInfo::setProperty() end // Source::inputTensorsInfo begin - + PlatformResult getInputTensorsInfo(int id, const std::string& name, int* res_id); // Source::inputTensorsInfo end // Source::inputData() begin @@ -124,6 +125,7 @@ class PipelineManager { // Valve::setOpen() end private: common::Instance* instance_ptr_; + TensorsInfoManager* tensors_info_manager_; std::map> pipelines_; }; diff --git a/src/ml/ml_pipeline_source.cc b/src/ml/ml_pipeline_source.cc new file mode 100644 index 0000000..7ac0104 --- /dev/null +++ b/src/ml/ml_pipeline_source.cc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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. + */ + +#include "ml_pipeline_source.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { +namespace pipeline { + +PlatformResult Source::CreateSource(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out) { + ScopeLogger("name: [%s], pipeline: [%p]", name.c_str(), pipeline); + ml_pipeline_src_h source_handle = nullptr; + auto ret = ml_pipeline_src_get_handle(pipeline, name.c_str(), &source_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_src_get_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get source"); + } + + out->reset(new (std::nothrow) Source{name, source_handle}); + if (!out) { + ret = ml_pipeline_src_release_handle(source_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_src_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_src_release_handle() succeeded"); + } + return LogAndCreateResult(ErrorCode::ABORT_ERR, "Could not get the source", + ("Could not allocate memory")); + } + + return PlatformResult{}; +} + +Source::Source(const std::string& name, ml_pipeline_src_h source_handle) + : name_{name}, source_{source_handle} { + ScopeLogger("name: [%s], handle: [%p]", name.c_str(), source_handle); +} + +Source::~Source() { + ScopeLogger("name: [%s], handle: [%p]", name_.c_str(), source_); + + auto ret = ml_pipeline_src_release_handle(source_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_src_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_src_release_handle() succeeded"); + } +} + +PlatformResult Source::getInputTensorsInfo(ml_tensors_info_h* result) { + ScopeLogger(); + + ml_tensors_info_h info = nullptr; + auto ret = ml_pipeline_src_get_tensors_info(source_, &info); + + if (ML_ERROR_NONE != ret) { + LoggerE(" ml_pipeline_src_get_tensors_info failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor info"); + } + + *result = info; + + return PlatformResult{}; +} + +} // namespace pipeline +} // namespace ml +} // namespace extension \ No newline at end of file diff --git a/src/ml/ml_pipeline_source.h b/src/ml/ml_pipeline_source.h new file mode 100644 index 0000000..cdd0154 --- /dev/null +++ b/src/ml/ml_pipeline_source.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed 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 ML_ML_PIPELINE_SOURCE_H_ +#define ML_ML_PIPELINE_SOURCE_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { +namespace pipeline { + +class Source { + public: + static PlatformResult CreateSource(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out); + + ~Source(); + + PlatformResult getInputTensorsInfo(ml_tensors_info_h* result); + + Source(const Source&) = delete; + Source& operator=(const Source&) = delete; + + private: + Source(const std::string& name, ml_pipeline_src_h source_handle); + const std::string name_; + const ml_pipeline_src_h source_; +}; + +} // namespace pipeline +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_SOURCE_H_ \ No newline at end of file -- 2.7.4