From c127487afb8ed75e5225cc29190cd53ec8b49214 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 1 Dec 2020 11:30:10 +0200 Subject: [PATCH 01/16] [Bluetooth] Prevent "Wrong listener identifier" errors for BLE scan The following app code caused aforementioned errors: var adapter = tizen.bluetooth.getLEAdapter(); adapter.startScan(); setTimeout(function() { adapter.stopScan(); }, 10000); Now, the error is not thrown. [Validation] tct-bluetooth-tizen-tests: auto: 100% pass rate, manual Bluetooth04_BLE_wearable suite: 100% pass rate The code above runs in ChromeDevTools without errors Change-Id: Id9ec278b4bb1c5ce38d0b3ffb1324498152ab645 Signed-off-by: Pawel Wasowski --- src/bluetooth/bluetooth_api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bluetooth/bluetooth_api.js b/src/bluetooth/bluetooth_api.js index 984fb77..1869e14 100755 --- a/src/bluetooth/bluetooth_api.js +++ b/src/bluetooth/bluetooth_api.js @@ -1514,12 +1514,12 @@ BluetoothLEAdapter.prototype.startScan = function() { BluetoothLEAdapter.prototype.stopScan = function() { privUtils_.log('Entered BluetoothLEAdapter.stopScan()'); - _bleScanListener.removeListener(); - var result = native.callSync('BluetoothLEAdapter_stopScan', {}); if (native.isFailure(result)) { throw native.getErrorObject(result); } + + _bleScanListener.removeListener(); }; var _BluetoothAdvertisePacketType = { -- 2.7.4 From b70a4532d7137e3566e1806558524fca343d2e01 Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Mon, 4 Jan 2021 12:47:12 +0100 Subject: [PATCH 02/16] [version] 2.46 Change-Id: I1d625296e33677999739d473d445b2c09d1ec4e7 --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 7f4bc76..7e6ed1d 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.45 +Version: 2.46 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From d5699286b81ab1d0f3d4f4322bc0ed8e797aa769 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 29 Dec 2020 16:56:01 +0100 Subject: [PATCH 03/16] [ML][utils] Add native error to PlatformResult converter [Verification] The code builds fine Change-Id: I88234f6474850f554dc617bb0ccc5343b6ed7e93 Signed-off-by: Pawel Wasowski --- src/ml/ml_utils.cc | 29 +++++++++++++++++++++++++++++ src/ml/ml_utils.h | 11 ++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/ml/ml_utils.cc b/src/ml/ml_utils.cc index 44987d8..7babe96 100644 --- a/src/ml/ml_utils.cc +++ b/src/ml/ml_utils.cc @@ -24,6 +24,35 @@ namespace extension { namespace ml { namespace util { +PlatformResult ToPlatformResult(int ml_error_code, const std::string& error_message_beginning) { + ScopeLogger("ml_error_code: [%d] (%s)", ml_error_code, get_error_message(ml_error_code)); + + switch (ml_error_code) { + case ML_ERROR_NONE: + return PlatformResult{}; + case ML_ERROR_INVALID_PARAMETER: + return PlatformResult{ErrorCode::INVALID_VALUES_ERR, + error_message_beginning + ": invalid parameter"}; + case ML_ERROR_PERMISSION_DENIED: + return PlatformResult{ErrorCode::SECURITY_ERR, + error_message_beginning + ": permission denied"}; + case ML_ERROR_TRY_AGAIN: + return PlatformResult{ErrorCode::INVALID_STATE_ERR, + error_message_beginning + ": invalid state"}; + case ML_ERROR_TIMED_OUT: + return PlatformResult{ErrorCode::TIMEOUT_ERR, error_message_beginning + ": timeout"}; + case ML_ERROR_NOT_SUPPORTED: + return PlatformResult{ErrorCode::NOT_SUPPORTED_ERR, + error_message_beginning + ": not supported"}; + case ML_ERROR_STREAMS_PIPE: + case ML_ERROR_UNKNOWN: + case ML_ERROR_OUT_OF_MEMORY: + default: + return PlatformResult{ErrorCode::ABORT_ERR, + error_message_beginning + ": an unknown error occurred"}; + } +} + using namespace common; } // util diff --git a/src/ml/ml_utils.h b/src/ml/ml_utils.h index 3424aad..725c7d9 100644 --- a/src/ml/ml_utils.h +++ b/src/ml/ml_utils.h @@ -17,12 +17,21 @@ #ifndef ML_ML_UTILS_H_ #define ML_ML_UTILS_H_ +#include + #include "common/picojson.h" #include "common/platform_result.h" +using common::PlatformResult; +using common::ErrorCode; + namespace extension { namespace ml { -namespace util {} // util +namespace util { + +PlatformResult ToPlatformResult(int ml_error_code, const std::string& error_message); + +} // util } // ml } // extension -- 2.7.4 From f55afdbe3cad75839a4374b70cca0d762556adbc Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Tue, 5 Jan 2021 14:27:05 +0100 Subject: [PATCH 04/16] [Common] Moved helper functions to decode/encode strings/binary to common [Verification] Built successfully. Metadata and filesystem auto tct 100%. Change-Id: I751e5cad95f8c7dc907214225f8f27cabbb3e5e7 Signed-off-by: Rafal Walczyna --- src/common/converter.cc | 37 ++++++++++++++++++++++++++ src/common/converter.h | 3 +++ src/filesystem/filesystem_instance.cc | 50 +++++------------------------------ src/metadata/metadata_instance.cc | 25 +++--------------- 4 files changed, 51 insertions(+), 64 deletions(-) diff --git a/src/common/converter.cc b/src/common/converter.cc index 48ccd60..ef59df0 100644 --- a/src/common/converter.cc +++ b/src/common/converter.cc @@ -43,4 +43,41 @@ long stol(const std::string& str, std::size_t* pos, int base) { } } +/* Write to str buf bytes as if they were UTF-8 codepoints */ +void encode_binary_in_string(const std::vector& buf, std::string& str) { + ScopeLogger(); + str.reserve(str.size() + buf.size()); + + for (std::uint8_t byte : buf) { + if (byte < 128) { + str += byte; + continue; + } + str += 0xC0 | (byte >> 6); + str += 0x80 | (byte & 0x3F); + } +} + +/* Decode (max 2-byte) UTF-8 characters to buf, throws std::runtime_error */ +void decode_binary_from_string(const std::string& str, std::vector& buf) { + ScopeLogger(); + buf.reserve(buf.size() + str.size()); + + const std::uint8_t* it = (std::uint8_t*)str.data(); + const std::uint8_t* end = it + str.size(); + while (it != end) { + if (*it < 128) { + buf.push_back(*it++); + continue; + } + auto b1 = *it++; + if (it == end) { + throw std::runtime_error("internal error (invalid UTF-8 sequence)"); + } + auto b2 = *it++; + unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F); + buf.push_back(x); + } +} + } // webapi diff --git a/src/common/converter.h b/src/common/converter.h index 35b9e1f..5ba7a6b 100644 --- a/src/common/converter.h +++ b/src/common/converter.h @@ -59,6 +59,9 @@ const T &FromJson(const picojson::object &in, const char *name, Names... names) return FromJson(v.get(), names...); } +void encode_binary_in_string(const std::vector& buf, std::string& str); +void decode_binary_from_string(const std::string& str, std::vector& buf); + } // common #endif // COMMON_CONVERTER_H_ diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index da8b0ab..010a202 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -23,6 +23,7 @@ #include #include +#include "common/converter.h" #include "common/logger.h" #include "common/picojson.h" #include "common/platform_exception.h" @@ -235,48 +236,11 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError)); } -/* Write to str buf bytes as if they were UTF-8 codepoints */ -static void encode_binary_in_string(const std::vector& buf, std::string& str) { - ScopeLogger(); - str.reserve(str.size() + buf.size()); - - for (std::uint8_t byte : buf) { - if (byte < 128) { - str += byte; - continue; - } - str += 0xC0 | (byte >> 6); - str += 0x80 | (byte & 0x3F); - } -} - -/* Decode (max 2-byte) UTF-8 characters to buf, throws std::runtime_error */ -static void decode_binary_from_string(const std::string& str, std::vector& buf) { - ScopeLogger(); - buf.reserve(buf.size() + str.size()); - - const std::uint8_t* it = (std::uint8_t*)str.data(); - const std::uint8_t* end = it + str.size(); - while (it != end) { - if (*it < 128) { - buf.push_back(*it++); - continue; - } - auto b1 = *it++; - if (it == end) { - throw std::runtime_error("internal error (invalid UTF-8 sequence)"); - } - auto b2 = *it++; - unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F); - buf.push_back(x); - } -} - namespace latin1 { -static auto to_utf8 = &encode_binary_in_string; +static auto to_utf8 = &common::encode_binary_in_string; /* It does not check if UTF-8 values are representable by ISO-8859-1. Make proper checks and * substitute invalid characters in JavaScript before passing through crosswalk */ -static auto from_utf8 = &decode_binary_from_string; +static auto from_utf8 = &common::decode_binary_from_string; } static constexpr std::size_t NPOS = (std::size_t)(-1); @@ -727,7 +691,7 @@ void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::ob std::vector out_data = read_file(location, offset, length); out["result"] = picojson::value(picojson::string_type, true); - encode_binary_in_string(out_data, out["result"].get()); + common::encode_binary_in_string(out_data, out["result"].get()); ReportSuccess(out); } catch (std::runtime_error& e) { LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what()); @@ -796,7 +760,7 @@ void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::o try { std::vector data; - decode_binary_from_string(str, data); + common::decode_binary_from_string(str, data); write_file(data.data(), data.size(), location, offset, mode); } catch (std::runtime_error& e) { LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what()); @@ -2142,7 +2106,7 @@ void FilesystemInstance::FileHandleReadData(const picojson::value& args, picojso try { std::vector data = read_file(handle->file_handle, size); out["result"] = picojson::value(picojson::string_type, true); - encode_binary_in_string(data, out["result"].get()); + common::encode_binary_in_string(data, out["result"].get()); } catch (std::runtime_error& e) { LoggerE("Cannot read, cause: %s", e.what()); LogAndReportError(IOException(e.what()), out); @@ -2188,7 +2152,7 @@ void FilesystemInstance::FileHandleWriteData(const picojson::value& args, picojs auto logic = [str, handle](decltype(out) out) { try { std::vector bytes; - decode_binary_from_string(str, bytes); + common::decode_binary_from_string(str, bytes); write_file(bytes.data(), bytes.size(), handle->file_handle); } catch (std::runtime_error& e) { LogAndReportError(IOException(e.what()), out); diff --git a/src/metadata/metadata_instance.cc b/src/metadata/metadata_instance.cc index eb8c02e..36d6fdf 100644 --- a/src/metadata/metadata_instance.cc +++ b/src/metadata/metadata_instance.cc @@ -16,6 +16,7 @@ #include "metadata/metadata_instance.h" +#include "common/converter.h" #include "common/logger.h" #include "common/picojson.h" #include "common/platform_exception.h" @@ -114,24 +115,6 @@ void MetadataInstance::MetadataFileHandleGet(const picojson::value& args, picojs ReportSuccess(picojson::value(value), out); } -// TODO copied from filesystem -// move to common?? -/* Write to str buf bytes as if they were UTF-8 codepoints */ -static void encode_binary_in_string(const std::vector& buf, std::string& str) { - ScopeLogger(); - str.reserve(str.size() + buf.size()); - - for (std::uint8_t byte : buf) { - if (byte < 128) { - str += byte; - continue; - } - str += 0xC0 | (byte >> 6); - str += 0x80 | (byte & 0x3F); - } -} -/////////////////////////////////// - void MetadataInstance::MetadataFileHandleGetArtwork(const picojson::value& args, picojson::object& out) { ScopeLogger(); @@ -165,7 +148,7 @@ void MetadataInstance::MetadataFileHandleGetArtwork(const picojson::value& args, picojson::object& result_artwork_obj = result_artwork.get(); result_artwork_obj["encodedData"] = picojson::value(picojson::string_type, true); - encode_binary_in_string(data, result_artwork_obj["encodedData"].get()); + common::encode_binary_in_string(data, result_artwork_obj["encodedData"].get()); result_artwork_obj["mimeType"] = picojson::value(mime_type); ReportSuccess(result_artwork, out); @@ -201,7 +184,7 @@ void MetadataInstance::MetadataFileHandleGetThumbnailFrame(const picojson::value } std::string result_artwork; - encode_binary_in_string(data, result_artwork); + common::encode_binary_in_string(data, result_artwork); ReportSuccess(picojson::value(result_artwork), out); } @@ -238,7 +221,7 @@ void MetadataInstance::MetadataFileHandleGetFrameAtTime(const picojson::value& a } std::string result_frame; - encode_binary_in_string(data, result_frame); + common::encode_binary_in_string(data, result_frame); ReportSuccess(picojson::value(result_frame), out); } -- 2.7.4 From d0bf72305dab751448a61b8179fa1aa7e6cacb4a Mon Sep 17 00:00:00 2001 From: Arkadiusz Pietraszek Date: Thu, 7 Jan 2021 20:32:28 +0100 Subject: [PATCH 05/16] [Download][TDAF-1353] Exception fix for 'start' function `start` function was returning unknown error exception instead of unsupported error in case when networkType in DownloadRequest wasn't supported by the device. Additionally fix enables null values to be used (in accordance with the documentation). [Verification] Code builds without errors. TCT suites deprecated, download and systeminfo pass rate: 100%. Tested in developer console on devices with telephony set to true and false. Below code was used with all network types, as well as invalid values. ``` var downloadRequest = new tizen.DownloadRequest( "http://download.tizen.org/tct/2_1/webapi-tizen-download-test-image-lq.png", null, null, "CELLULAR", null); tizen.download.start(downloadRequest); ``` Change-Id: I4f2866a07019f129c852024970783b110ef11abc Signed-off-by: Arkadiusz Pietraszek --- src/download/download_api.js | 23 ++++++++++++++++++++--- src/download/download_instance.cc | 11 ++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/download/download_api.js b/src/download/download_api.js index 5ea0cf7..826ab87 100755 --- a/src/download/download_api.js +++ b/src/download/download_api.js @@ -90,12 +90,29 @@ tizen.DownloadRequest = function(url, destination, fileName, networkType, httpHe validator_.isConstructorCall(this, tizen.DownloadRequest); var url_ = converter_.toString(url); - var destination_ = destination === undefined ? '' : converter_.toString(destination); - var fileName_ = fileName === undefined ? '' : converter_.toString(fileName); + var destination_; + + if (undefined === destination || null === destination) { + destination_ = ''; + } else { + destination_ = converter_.toString(destination); + } + + var fileName_; + + if (undefined === fileName || null === fileName) { + fileName_ = ''; + } else { + fileName_ = converter_.toString(fileName); + } var networkType_; - if (networkType === undefined || !(networkType in DownloadNetworkType)) { + if ( + undefined === networkType || + null === networkType || + !(networkType in DownloadNetworkType) + ) { networkType_ = 'ALL'; } else { networkType_ = networkType; diff --git a/src/download/download_instance.cc b/src/download/download_instance.cc index 49905f5..3a3b6c3 100644 --- a/src/download/download_instance.cc +++ b/src/download/download_instance.cc @@ -492,6 +492,8 @@ common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::strin bool& network_support, bool& network_available, DownloadInfoPtr di_ptr) { + ScopeLogger("network_type: %s", network_type.c_str()); + connection_h connection = nullptr; int ret = connection_create(&connection); CHECK_CONNECTION_ERROR(ret) @@ -503,11 +505,6 @@ common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::strin ret = connection_get_type(connection, &connection_type); CHECK_CONNECTION_ERROR(ret) - if (CONNECTION_TYPE_DISCONNECTED == connection_type) { - return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred", - ("Connection type is disconnected")); - } - if ("CELLULAR" == network_type) { // check if connection type is supported bool cell_support = false; @@ -549,6 +546,10 @@ common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::strin "The input parameter contains an invalid network type.", ("The input parameter contains an invalid network type: %s", network_type.c_str())); } + if (CONNECTION_TYPE_DISCONNECTED == connection_type) { + return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred", + ("Connection type is disconnected")); + } return common::PlatformResult(common::ErrorCode::NO_ERROR); } #undef CHECK_CONNECTION_ERROR -- 2.7.4 From 30e2dbdb931f462485663079e656c3e0eb8517f6 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Fri, 8 Jan 2021 12:06:03 +0100 Subject: [PATCH 06/16] [ML][pipeline] Add placeholders for implementation ACR: TWDAPI-274 This commit adds placeholders for implementation of PipelineManager and Pipeline to avoid merge conflicts of changes done by different committers. [Verification] Code compiles Change-Id: Id4a2b33943e390526929bb5c2dba42cd55d7ad12 Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 76 ++++++++++++++++++++++++++++++++++++++ src/ml/ml_instance.cc | 74 +++++++++++++++++++++++++++++++++++++ src/ml/ml_instance.h | 76 ++++++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline.cc | 77 +++++++++++++++++++++++++++++++++++++- src/ml/ml_pipeline.h | 86 +++++++++++++++++++++++++++++++++++++++++-- src/ml/ml_pipeline_manager.cc | 78 ++++++++++++++++++++++++++++++++++++++- src/ml/ml_pipeline_manager.h | 86 +++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 545 insertions(+), 8 deletions(-) diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index 1aa4728..fdd1a2d 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -14,6 +14,82 @@ * limitations under the License. */ +//PipelineManager::createPipeline() begin + +//PipelineManager::createPipeline() end + +//Pipeline::state begin + +//Pipeline::state end + +//Pipeline::start() begin + +//Pipeline::start() end + +//Pipeline::stop() begin + +//Pipeline::stop() end + +//Pipeline::dispose() begin + +//Pipeline::dispose() end + +//Pipeline::getNodeInfo() begin + +//Pipeline::getNodeInfo() end + +//Pipeline::getSource() begin + +//Pipeline::getSource() end + +//Pipeline::getSwitch() begin + +//Pipeline::getSwitch() end + +//Pipeline::getValve() begin + +//Pipeline::getValve() end + +//Pipeline::registerSinkCallback() begin + +//Pipeline::registerSinkCallback() end + +//Pipeline::unregisterSinkCallback() begin + +//Pipeline::unregisterSinkCallback() end + +//Pipeline::registerCustomFilter() begin + +//Pipeline::registerCustomFilter() end + +//Pipeline::unregisterCustomFilter() begin + +//Pipeline::unregisterCustomFilter() end + +//NodeInfo::getProperty() begin + +//NodeInfo::getProperty() end + +//NodeInfo::setProperty() begin + +//NodeInfo::setProperty() end + +//Source::inputTensorsInfo begin + +//Source::inputTensorsInfo end + +//Source::inputData() begin + +//Source::inputData() end + +//Switch::getPadList() begin + +//Switch::getPadList() end + +//Valve::setOpen() begin + +//Valve::setOpen() end + var MachineLearningPipeline = function() {}; // ML Pipeline API diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index ec1e267..5706267 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -58,7 +58,81 @@ MlInstance::~MlInstance() { // Single API end // Pipeline API begin +// PipelineManager::createPipeline() begin +// PipelineManager::createPipeline() end + +// Pipeline::state begin + +// Pipeline::state end + +// Pipeline::start() begin + +// Pipeline::start() end + +// Pipeline::stop() begin + +// Pipeline::stop() end + +// Pipeline::dispose() begin + +// Pipeline::dispose() end + +// Pipeline::getNodeInfo() begin + +// Pipeline::getNodeInfo() end + +// Pipeline::getSource() begin + +// Pipeline::getSource() end + +// Pipeline::getSwitch() begin + +// Pipeline::getSwitch() end + +// Pipeline::getValve() begin + +// Pipeline::getValve() end + +// Pipeline::registerSinkCallback() begin + +// Pipeline::registerSinkCallback() end + +// Pipeline::unregisterSinkCallback() begin + +// Pipeline::unregisterSinkCallback() end + +// Pipeline::registerCustomFilter() begin + +// Pipeline::registerCustomFilter() end + +// Pipeline::unregisterCustomFilter() begin + +// Pipeline::unregisterCustomFilter() end + +// NodeInfo::getProperty() begin + +// NodeInfo::getProperty() end + +// NodeInfo::setProperty() begin + +// NodeInfo::setProperty() end + +// Source::inputTensorsInfo begin + +// Source::inputTensorsInfo end + +// Source::inputData() begin + +// Source::inputData() end + +// Switch::getPadList() begin + +// Switch::getPadList() end + +// Valve::setOpen() begin + +// Valve::setOpen() end // Pipeline API end } // namespace ml diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index fc179d2..e7a1998 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -41,6 +41,82 @@ class MlInstance : public common::ParsedInstance { // Pipeline API begin + // PipelineManager::createPipeline() begin + + // PipelineManager::createPipeline() end + + // Pipeline::state begin + + // Pipeline::state end + + // Pipeline::start() begin + + // Pipeline::start() end + + // Pipeline::stop() begin + + // Pipeline::stop() end + + // Pipeline::dispose() begin + + // Pipeline::dispose() end + + // Pipeline::getNodeInfo() begin + + // Pipeline::getNodeInfo() end + + // Pipeline::getSource() begin + + // Pipeline::getSource() end + + // Pipeline::getSwitch() begin + + // Pipeline::getSwitch() end + + // Pipeline::getValve() begin + + // Pipeline::getValve() end + + // Pipeline::registerSinkCallback() begin + + // Pipeline::registerSinkCallback() end + + // Pipeline::unregisterSinkCallback() begin + + // Pipeline::unregisterSinkCallback() end + + // Pipeline::registerCustomFilter() begin + + // Pipeline::registerCustomFilter() end + + // Pipeline::unregisterCustomFilter() begin + + // Pipeline::unregisterCustomFilter() end + + // NodeInfo::getProperty() begin + + // NodeInfo::getProperty() end + + // NodeInfo::setProperty() begin + + // NodeInfo::setProperty() end + + // Source::inputTensorsInfo begin + + // Source::inputTensorsInfo end + + // Source::inputData() begin + + // Source::inputData() end + + // Switch::getPadList() begin + + // Switch::getPadList() end + + // Valve::setOpen() begin + + // Valve::setOpen() end + // Pipeline API end }; diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index f931b81..60a0108 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -13,5 +13,80 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "ml_pipeline.h" -#include "ml_pipeline.h" \ No newline at end of file +// PipelineManager::createPipeline() begin + +// PipelineManager::createPipeline() end + +// Pipeline::state begin + +// Pipeline::state end + +// Pipeline::start() begin + +// Pipeline::start() end + +// Pipeline::stop() begin + +// Pipeline::stop() end + +// Pipeline::dispose() begin + +// Pipeline::dispose() end + +// Pipeline::getNodeInfo() begin + +// Pipeline::getNodeInfo() end + +// Pipeline::getSource() begin + +// Pipeline::getSource() end + +// Pipeline::getSwitch() begin + +// Pipeline::getSwitch() end + +// Pipeline::getValve() begin + +// Pipeline::getValve() end + +// Pipeline::registerSinkCallback() begin + +// Pipeline::registerSinkCallback() end + +// Pipeline::unregisterSinkCallback() begin + +// Pipeline::unregisterSinkCallback() end + +// Pipeline::registerCustomFilter() begin + +// Pipeline::registerCustomFilter() end + +// Pipeline::unregisterCustomFilter() begin + +// Pipeline::unregisterCustomFilter() end + +// NodeInfo::getProperty() begin + +// NodeInfo::getProperty() end + +// NodeInfo::setProperty() begin + +// NodeInfo::setProperty() end + +// Source::inputTensorsInfo begin + +// Source::inputTensorsInfo end + +// Source::inputData() begin + +// Source::inputData() end + +// Switch::getPadList() begin + +// Switch::getPadList() end + +// Valve::setOpen() begin + +// Valve::setOpen() end \ No newline at end of file diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index e277044..029269e 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -23,7 +23,87 @@ namespace extension { namespace ml { -} // namespace ml -} // namespace extension +class Pipeline { + public: + // PipelineManager::createPipeline() begin -#endif // ML_ML_PIPELINE_H_ \ No newline at end of file + // PipelineManager::createPipeline() end + + // Pipeline::state begin + + // Pipeline::state end + + // Pipeline::start() begin + + // Pipeline::start() end + + // Pipeline::stop() begin + + // Pipeline::stop() end + + // Pipeline::dispose() begin + + // Pipeline::dispose() end + + // Pipeline::getNodeInfo() begin + + // Pipeline::getNodeInfo() end + + // Pipeline::getSource() begin + + // Pipeline::getSource() end + + // Pipeline::getSwitch() begin + + // Pipeline::getSwitch() end + + // Pipeline::getValve() begin + + // Pipeline::getValve() end + + // Pipeline::registerSinkCallback() begin + + // Pipeline::registerSinkCallback() end + + // Pipeline::unregisterSinkCallback() begin + + // Pipeline::unregisterSinkCallback() end + + // Pipeline::registerCustomFilter() begin + + // Pipeline::registerCustomFilter() end + + // Pipeline::unregisterCustomFilter() begin + + // Pipeline::unregisterCustomFilter() end + + // NodeInfo::getProperty() begin + + // NodeInfo::getProperty() end + + // NodeInfo::setProperty() begin + + // NodeInfo::setProperty() end + + // Source::inputTensorsInfo begin + + // Source::inputTensorsInfo end + + // Source::inputData() begin + + // Source::inputData() end + + // Switch::getPadList() begin + + // Switch::getPadList() end + + // Valve::setOpen() begin + + // Valve::setOpen() end + private: +}; + +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_H_ \ No newline at end of file diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index dcba44c..b33a771 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -14,4 +14,80 @@ * limitations under the License. */ -#include "ml_pipeline_manager.h" \ No newline at end of file +#include "ml_pipeline_manager.h" + +// PipelineManager::createPipeline() begin + +// PipelineManager::createPipeline() end + +// Pipeline::state begin + +// Pipeline::state end + +// Pipeline::start() begin + +// Pipeline::start() end + +// Pipeline::stop() begin + +// Pipeline::stop() end + +// Pipeline::dispose() begin + +// Pipeline::dispose() end + +// Pipeline::getNodeInfo() begin + +// Pipeline::getNodeInfo() end + +// Pipeline::getSource() begin + +// Pipeline::getSource() end + +// Pipeline::getSwitch() begin + +// Pipeline::getSwitch() end + +// Pipeline::getValve() begin + +// Pipeline::getValve() end + +// Pipeline::registerSinkCallback() begin + +// Pipeline::registerSinkCallback() end + +// Pipeline::unregisterSinkCallback() begin + +// Pipeline::unregisterSinkCallback() end + +// Pipeline::registerCustomFilter() begin + +// Pipeline::registerCustomFilter() end + +// Pipeline::unregisterCustomFilter() begin + +// Pipeline::unregisterCustomFilter() end + +// NodeInfo::getProperty() begin + +// NodeInfo::getProperty() end + +// NodeInfo::setProperty() begin + +// NodeInfo::setProperty() end + +// Source::inputTensorsInfo begin + +// Source::inputTensorsInfo end + +// Source::inputData() begin + +// Source::inputData() end + +// Switch::getPadList() begin + +// Switch::getPadList() end + +// Valve::setOpen() begin + +// Valve::setOpen() end \ No newline at end of file diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index c068daf..68891e3 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -23,7 +23,87 @@ namespace extension { namespace ml { -} // namespace ml -} // namespace extension +class PipelineManager { + public: + // PipelineManager::createPipeline() begin -#endif // ML_ML_PIPELINE_MANAGER_H_ \ No newline at end of file + // PipelineManager::createPipeline() end + + // Pipeline::state begin + + // Pipeline::state end + + // Pipeline::start() begin + + // Pipeline::start() end + + // Pipeline::stop() begin + + // Pipeline::stop() end + + // Pipeline::dispose() begin + + // Pipeline::dispose() end + + // Pipeline::getNodeInfo() begin + + // Pipeline::getNodeInfo() end + + // Pipeline::getSource() begin + + // Pipeline::getSource() end + + // Pipeline::getSwitch() begin + + // Pipeline::getSwitch() end + + // Pipeline::getValve() begin + + // Pipeline::getValve() end + + // Pipeline::registerSinkCallback() begin + + // Pipeline::registerSinkCallback() end + + // Pipeline::unregisterSinkCallback() begin + + // Pipeline::unregisterSinkCallback() end + + // Pipeline::registerCustomFilter() begin + + // Pipeline::registerCustomFilter() end + + // Pipeline::unregisterCustomFilter() begin + + // Pipeline::unregisterCustomFilter() end + + // NodeInfo::getProperty() begin + + // NodeInfo::getProperty() end + + // NodeInfo::setProperty() begin + + // NodeInfo::setProperty() end + + // Source::inputTensorsInfo begin + + // Source::inputTensorsInfo end + + // Source::inputData() begin + + // Source::inputData() end + + // Switch::getPadList() begin + + // Switch::getPadList() end + + // Valve::setOpen() begin + + // Valve::setOpen() end + private: +}; + +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_MANAGER_H_ \ No newline at end of file -- 2.7.4 From cc19a7e5900e145c01e9b7ba21c2f2bb76ec42f6 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Thu, 24 Dec 2020 11:36:26 +0100 Subject: [PATCH 07/16] [ML][Pipeline] Add Pipeline and PipelineManager ACR: TWDAPI-274 [Verification] createPipeline() tested in Chrome DevTools with the snippet below works fine var pipeline = tizen.ml.pipeline.createPipeline( 'videoteststrc ! tizenwlsink', function(state) { console.log(state); }) //a moment later: // READY // PAUSED tizen.ml.createPipeline() // WebAPIException: InvalidValuesError Change-Id: I68beaebf7e248b61bba9dc06ce6124c187c45fae Signed-off-by: Pawel Wasowski --- src/ml/js/ml_common.js | 3 ++ src/ml/js/ml_pipeline.js | 96 +++++++++++++++++++++++++++++++-- src/ml/ml_instance.cc | 63 +++++++++++++++++++--- src/ml/ml_instance.h | 5 +- src/ml/ml_pipeline.cc | 120 +++++++++++++++++++++++++++++++++++++++++- src/ml/ml_pipeline.h | 32 ++++++++++- src/ml/ml_pipeline_manager.cc | 44 +++++++++++++++- src/ml/ml_pipeline_manager.h | 18 ++++++- 8 files changed, 364 insertions(+), 17 deletions(-) diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 21819da..c8bc981 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -17,6 +17,9 @@ var privUtils_ = xwalk.utils; var validator_ = privUtils_.validator; var types_ = validator_.Types; +var native_ = new xwalk.utils.NativeManager(extension); + +var AbortError = new WebAPIException('AbortError', 'An unknown error occurred'); // TensorRawData diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index fdd1a2d..f50b97a 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -14,12 +14,101 @@ * limitations under the License. */ -//PipelineManager::createPipeline() begin +var kPipelineStateChangeListenerNamePrefix = 'MLPipelineStateChangeListener'; +//PipelineManager::createPipeline() begin +var nextPipelineId = 1; +function NextPipelineId() { + return nextPipelineId++; +} + +var ValidPipelineManagerCreatePipelineExceptions = [ + 'InvalidValuesError', + 'TypeMismatchError', + 'NotSupportedError', + 'SecurityError', + 'AbortError' +]; + +var CreatePipeline = function() { + privUtils_.log('Entered PipelineManager.createPipeline()'); + var args = validator_.validateArgs(arguments, [ + { + name: 'definition', + type: validator_.Types.STRING + }, + { + name: 'listener', + type: validator_.Types.FUNCTION, + optional: true, + nullable: true + } + ]); + + if (!args.has.definition) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: pipeline definition is mandatory' + ); + } + + var pipeline = new Pipeline(NextPipelineId()); + var nativeArgs = { + id: pipeline._id, + definition: args.definition + }; + + if (args.listener) { + nativeArgs.listenerName = kPipelineStateChangeListenerNamePrefix + pipeline._id; + var stateChangeListener = function(stateObject) { + args.listener(stateObject.state); + }; + native_.addListener(nativeArgs.listenerName, stateChangeListener); + } + + var result = native_.callSync('MLPipelineManagerCreatePipeline', nativeArgs); + + if (native_.isFailure(result)) { + if (nativeArgs.listenerName) { + native_.removeListener(nativeArgs.listenerName); + } + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineManagerCreatePipelineExceptions, + AbortError + ); + } + + return pipeline; +}; //PipelineManager::createPipeline() end //Pipeline::state begin - +var ValidPipelineStateExceptions = ['NotSupportedError', 'AbortError']; +var Pipeline = function(id) { + Object.defineProperties(this, { + state: { + enumerable: true, + get: function() { + var result = native_.callSync('MLPipelineGetState', { + id: id + }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineStateExceptions, + AbortError + ); + } + + return result.state; + } + }, + _id: { + value: id + } + }); +}; //Pipeline::state end //Pipeline::start() begin @@ -89,7 +178,8 @@ //Valve::setOpen() begin //Valve::setOpen() end - var MachineLearningPipeline = function() {}; +MachineLearningPipeline.prototype.createPipeline = CreatePipeline; + // ML Pipeline API diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 5706267..5d2f242 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -24,21 +24,22 @@ namespace ml { using namespace common; -MlInstance::MlInstance() { +MlInstance::MlInstance() : pipeline_manager_{this} { ScopeLogger(); using namespace std::placeholders; #define REGISTER_METHOD(M) RegisterSyncHandler(#M, std::bind(&MlInstance::M, this, _1, _2)) -// Common ML API begin + // Common ML API begin -// Common ML API end + // Common ML API end -// Single API begin + // Single API begin -// Single API end + // Single API end -// Pipeline API begin + // Pipeline API begin + REGISTER_METHOD(MLPipelineManagerCreatePipeline); // Pipeline API end @@ -58,8 +59,57 @@ MlInstance::~MlInstance() { // Single API end // Pipeline API begin + +namespace { + +const std::string kId = "id"; +const std::string kDefinition = "definition"; +const std::string kPipelineStateChangeListenerName = "listenerName"; + +} // namespace + // PipelineManager::createPipeline() begin +namespace { + +bool CreatePipelineArgumentsAreInvalid(const picojson::value& args) { + ScopeLogger(); + auto arguments_valid = args.get(kId).is(); + arguments_valid &= args.get(kDefinition).is(); + arguments_valid &= (args.get(kPipelineStateChangeListenerName).is() || + args.get(kPipelineStateChangeListenerName).is()); + LoggerD("CreatePipeline arguments are %s", arguments_valid ? "valid" : "invalid"); + + return !arguments_valid; +} + +}; // namespace + +void MlInstance::MLPipelineManagerCreatePipeline(const picojson::value& args, + picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + + if (CreatePipelineArgumentsAreInvalid(args)) { + ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Could not create pipeline"}, &out); + return; + } + + auto id = static_cast(args.get(kId).get()); + auto definition = args.get(kDefinition).get(); + auto state_change_listener_name = + args.get(kPipelineStateChangeListenerName).is() + ? args.get(kPipelineStateChangeListenerName).get() + : ""; + + auto ret = pipeline_manager_.CreatePipeline(id, definition, state_change_listener_name); + + if (!ret) { + ReportError(ret, &out); + return; + } + + ReportSuccess(out); +} // PipelineManager::createPipeline() end // Pipeline::state begin @@ -133,6 +183,7 @@ MlInstance::~MlInstance() { // Valve::setOpen() begin // Valve::setOpen() end + // Pipeline API end } // namespace ml diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index e7a1998..622bcc8 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -19,6 +19,7 @@ #include "common/extension.h" +#include "ml/ml_pipeline_manager.h" #include "nnstreamer/nnstreamer-single.h" #include "nnstreamer/nnstreamer.h" @@ -40,9 +41,10 @@ class MlInstance : public common::ParsedInstance { // Single API end // Pipeline API begin + PipelineManager pipeline_manager_; // PipelineManager::createPipeline() begin - + void MLPipelineManagerCreatePipeline(const picojson::value& args, picojson::object& out); // PipelineManager::createPipeline() end // Pipeline::state begin @@ -116,7 +118,6 @@ class MlInstance : public common::ParsedInstance { // Valve::setOpen() begin // Valve::setOpen() end - // Pipeline API end }; diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 60a0108..caa63a5 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -13,12 +13,125 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include + +#include "common/logger.h" +#include "common/picojson.h" #include "ml_pipeline.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace { + +const std::string kListenerId = "listenerId"; +const std::string kState = "state"; + +std::string StateToString(ml_pipeline_state_e state) { + ScopeLogger("state: [%d]", state); + + std::string state_str; + switch (state) { + case ML_PIPELINE_STATE_UNKNOWN: + state_str = "UNKNOWN"; + break; + case ML_PIPELINE_STATE_NULL: + state_str = "NULL"; + break; + case ML_PIPELINE_STATE_READY: + state_str = "READY"; + break; + case ML_PIPELINE_STATE_PAUSED: + state_str = "PAUSED"; + break; + case ML_PIPELINE_STATE_PLAYING: + state_str = "PLAYING"; + break; + default: + LoggerE("Illegal ml_pipeline_state_e value: [%d]", state); + state_str = "UNKNOWN"; + } + + LoggerD("state_str: [%s]", state_str.c_str()); + return state_str; +} + +} // namespace + +namespace extension { +namespace ml { + +Pipeline::Pipeline(int id, const std::string& state_change_listener_name, + common::Instance* instance_ptr) + : id_{id}, + pipeline_{nullptr}, // this will be set to a proper pointer in CreatePipeline() + state_change_listener_name_{state_change_listener_name}, + instance_ptr_{instance_ptr} { + ScopeLogger("id: [%d], state_change_listener_name: [%s]", id, state_change_listener_name.c_str()); +} // PipelineManager::createPipeline() begin - +PlatformResult Pipeline::CreatePipeline(int id, const std::string& definition, + const std::string& state_change_listener_name, + common::Instance* instance_ptr, + std::unique_ptr* out) { + ScopeLogger("id: [%d], definition: [%s], state_change_listener_name: [%s]", id, + definition.c_str(), state_change_listener_name.c_str()); + + /* We need to create the Pipeline object before setting its pipeline_ member, + * because Pipeline is the user data for the listener registered by + * ml_pipeline_construct(). + */ + std::unique_ptr pipeline_ptr{ + new (std::nothrow) Pipeline{id, state_change_listener_name, instance_ptr}}; + if (!pipeline_ptr) { + return LogAndCreateResult(ErrorCode::ABORT_ERR, "An unknown occurred.", + ("Could not allocate memory for Pipeline")); + } + + int ret = ML_ERROR_UNKNOWN; + if (state_change_listener_name == "") { + ret = ml_pipeline_construct(definition.c_str(), nullptr, nullptr, &pipeline_ptr->pipeline_); + } else { + ret = ml_pipeline_construct(definition.c_str(), PipelineStateChangeListener, + static_cast(pipeline_ptr.get()), &pipeline_ptr->pipeline_); + } + + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_construct() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not create a pipeline"); + } + LoggerD("ml_pipeline_construct() succeeded"); + + *out = std::move(pipeline_ptr); + return PlatformResult{}; +} // PipelineManager::createPipeline() end +Pipeline::~Pipeline() { + ScopeLogger("Destroying pipeline: [%d]", id_); + + auto ret = ml_pipeline_destroy(pipeline_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); + } + LoggerD("ml_pipeline_destroy() succeeded"); +} + +void Pipeline::PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data) { + ScopeLogger("state: [%s]", StateToString(state).c_str()); + + Pipeline* pipeline = static_cast(user_data); + + picojson::value response{picojson::object{}}; + response.get()[kListenerId] = + picojson::value{pipeline->state_change_listener_name_}; + response.get()[kState] = picojson::value{StateToString(state)}; + + common::Instance::PostMessage(pipeline->instance_ptr_, response); +} + // Pipeline::state begin // Pipeline::state end @@ -89,4 +202,7 @@ // Valve::setOpen() begin -// Valve::setOpen() end \ No newline at end of file +// Valve::setOpen() end + +} // namespace extension +} // namespace ml diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 029269e..b5834f4 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -17,18 +17,40 @@ #ifndef ML_ML_PIPELINE_H_ #define ML_ML_PIPELINE_H_ +#include +#include + +#include + +#include "common/extension.h" #include "common/picojson.h" #include "common/platform_result.h" +using common::PlatformResult; + namespace extension { namespace ml { class Pipeline { public: // PipelineManager::createPipeline() begin - + /* + * We use a static function to create Pipeline objects, instead of + * a typical constructor, to be able to return an error without + * throwing a C++ exception. + */ + static PlatformResult CreatePipeline(int id, const std::string& definition, + const std::string& state_change_listener_name, + common::Instance* instance_ptr, + std::unique_ptr* out); // PipelineManager::createPipeline() end + Pipeline() = delete; + Pipeline(const Pipeline&) = delete; + Pipeline& operator=(const Pipeline&) = delete; + + ~Pipeline(); + // Pipeline::state begin // Pipeline::state end @@ -101,6 +123,14 @@ class Pipeline { // Valve::setOpen() end private: + Pipeline(int id, const std::string& state_change_listener_name, common::Instance* instance_ptr); + + const int id_; + ml_pipeline_h pipeline_; + const std::string state_change_listener_name_; + common::Instance* instance_ptr_; + + static void PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data); }; } // namespace ml diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index b33a771..1a21516 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -15,9 +15,46 @@ */ #include "ml_pipeline_manager.h" +#include "common/tools.h" -// PipelineManager::createPipeline() begin +using common::PlatformResult; +using common::ErrorCode; +using common::tools::ReportError; +using common::tools::ReportSuccess; + +namespace extension { +namespace ml { + +PipelineManager::PipelineManager(common::Instance* instance_ptr) : instance_ptr_{instance_ptr} { + ScopeLogger(); +} +PipelineManager::~PipelineManager() { + ScopeLogger(); +} + +// PipelineManager::createPipeline() begin +PlatformResult PipelineManager::CreatePipeline(int id, const std::string& definition, + const std::string& state_change_listener_name) { + ScopeLogger("id: [%d], definition: [%s], state_change_listener_name: [%s]", id, + definition.c_str(), state_change_listener_name.c_str()); + + if (pipelines_.count(id)) { + LoggerD("The pipeline already exists: [%d]", id); + return PlatformResult{ErrorCode::ABORT_ERR, "Could not create pipeline"}; + } + + std::unique_ptr pipeline_ptr; + auto ret = Pipeline::CreatePipeline(id, definition, state_change_listener_name, instance_ptr_, + &pipeline_ptr); + if (!ret) { + return ret; + } + + pipelines_.insert({id, std::move(pipeline_ptr)}); + + return PlatformResult{}; +} // PipelineManager::createPipeline() end // Pipeline::state begin @@ -90,4 +127,7 @@ // Valve::setOpen() begin -// Valve::setOpen() end \ No newline at end of file +// Valve::setOpen() end + +} // namespace ml +} // namespace extension diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 68891e3..1ecf79a 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -17,16 +17,30 @@ #ifndef ML_ML_PIPELINE_MANAGER_H_ #define ML_ML_PIPELINE_MANAGER_H_ +#include "common/extension.h" #include "common/picojson.h" #include "common/platform_result.h" +#include "ml_pipeline.h" + +using common::PlatformResult; + namespace extension { namespace ml { class PipelineManager { public: - // PipelineManager::createPipeline() begin + PipelineManager(common::Instance* instance_ptr); + ~PipelineManager(); + + PipelineManager() = delete; + PipelineManager(const PipelineManager&) = delete; + PipelineManager& operator=(const PipelineManager&) = delete; + + // PipelineManager::createPipeline() begin + PlatformResult CreatePipeline(int id, const std::string& definition, + const std::string& state_change_listener_name); // PipelineManager::createPipeline() end // Pipeline::state begin @@ -101,6 +115,8 @@ class PipelineManager { // Valve::setOpen() end private: + common::Instance* instance_ptr_; + std::map> pipelines_; }; } // namespace ml -- 2.7.4 From d93afde88134848383dd8843a18c29b2535f5995 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Mon, 4 Jan 2021 10:59:39 +0100 Subject: [PATCH 08/16] [ML][pipeline] Implement Pipeline::state getter ACR: TWDAPI-274 [Verification] Tested in Chrome DevTools with the snippets below. Works fine var pipeline = tizen.ml.pipeline.createPipeline('videotestsrc ! tizenwlsink', function(state) {console.log(state);}) pipeline.state Change-Id: Iae5e70c63d5c9fd98877defe0949024516c8c41d Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 2 +- src/ml/ml_instance.cc | 20 ++++++++++++++++++++ src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 13 +++++++++++++ src/ml/ml_pipeline.h | 2 +- src/ml/ml_pipeline_manager.cc | 12 ++++++++++++ src/ml/ml_pipeline_manager.h | 2 +- 7 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index f50b97a..3472be1 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -101,7 +101,7 @@ var Pipeline = function(id) { ); } - return result.state; + return result.result; } }, _id: { diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 5d2f242..0576dac 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -40,6 +40,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { // Pipeline API begin REGISTER_METHOD(MLPipelineManagerCreatePipeline); + REGISTER_METHOD(MLPipelineGetState); // Pipeline API end @@ -113,7 +114,26 @@ void MlInstance::MLPipelineManagerCreatePipeline(const picojson::value& args, // PipelineManager::createPipeline() end // Pipeline::state begin +void MlInstance::MLPipelineGetState(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; + } + auto id = static_cast(args.get(kId).get()); + picojson::value state_value{std::string{}}; + std::string* state_ptr = &state_value.get(); + auto ret = pipeline_manager_.GetPipelineState(id, state_ptr); + if (!ret) { + ReportError(ret, &out); + return; + } + + ReportSuccess(state_value, out); +} // Pipeline::state end // Pipeline::start() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 622bcc8..7bb28f4 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -48,7 +48,7 @@ class MlInstance : public common::ParsedInstance { // PipelineManager::createPipeline() end // Pipeline::state begin - + void MLPipelineGetState(const picojson::value& args, picojson::object& out); // Pipeline::state end // Pipeline::start() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index caa63a5..6faec44 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -133,7 +133,20 @@ void Pipeline::PipelineStateChangeListener(ml_pipeline_state_e state, void* user } // Pipeline::state begin +PlatformResult Pipeline::GetState(std::string* out) { + ScopeLogger("id_: [%d]", id_); + ml_pipeline_state_e state = ML_PIPELINE_STATE_UNKNOWN; + auto ret = ml_pipeline_get_state(pipeline_, &state); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_get_state() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get pipeline state"); + } + LoggerD("ml_pipeline_get_state() succeeded"); + + *out = StateToString(state); + return PlatformResult{}; +} // Pipeline::state end // Pipeline::start() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index b5834f4..c29f244 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -52,7 +52,7 @@ class Pipeline { ~Pipeline(); // Pipeline::state begin - + PlatformResult GetState(std::string* out); // Pipeline::state end // Pipeline::start() begin diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index 1a21516..2d4781c 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -58,7 +58,19 @@ PlatformResult PipelineManager::CreatePipeline(int id, const std::string& defini // PipelineManager::createPipeline() end // Pipeline::state begin +PlatformResult PipelineManager::GetPipelineState(int id, std::string* out) { + ScopeLogger("id: [%d]", id); + + auto pipeline_it = pipelines_.find(id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", id); + *out = "NULL"; + return PlatformResult{}; + } + auto ret = pipeline_it->second->GetState(out); + return ret; +} // Pipeline::state end // Pipeline::start() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 1ecf79a..f3e0293 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -44,7 +44,7 @@ class PipelineManager { // PipelineManager::createPipeline() end // Pipeline::state begin - + PlatformResult GetPipelineState(int id, std::string* out); // Pipeline::state end // Pipeline::start() begin -- 2.7.4 From b65eb2c6edc9d7f1aeb9dfd5aaa4344eeed6ee64 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 5 Jan 2021 22:47:17 +0100 Subject: [PATCH 09/16] [ML][pipeline] Implement Pipeline::dispose() ACR: TWDAPI-274 [Verification] Tested in Chrome DevTools with the snippet below, works fine. var pipeline = tizen.ml.pipeline.createPipeline('videotestsrc ! tizenwlsink', function(state) {console.log(state);}) // test screen appears pipeline.dispose() // no errors, test screen disappears Change-Id: I5401c3210f73619d5577380abf17139fadc390f1 Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 12 ++++++++++++ src/ml/ml_instance.cc | 21 +++++++++++++++++++-- src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 18 ++++++++++++++++++ src/ml/ml_pipeline.h | 2 +- src/ml/ml_pipeline_manager.cc | 20 ++++++++++++++++++++ src/ml/ml_pipeline_manager.h | 2 +- 7 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index 3472be1..e9debd3 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -17,6 +17,8 @@ var kPipelineStateChangeListenerNamePrefix = 'MLPipelineStateChangeListener'; //PipelineManager::createPipeline() begin +var ValidPipelineDisposeExceptions = ['NotFoundError', 'NotSupportedError', 'AbortError']; + var nextPipelineId = 1; function NextPipelineId() { return nextPipelineId++; @@ -120,7 +122,17 @@ var Pipeline = function(id) { //Pipeline::stop() end //Pipeline::dispose() begin +Pipeline.prototype.dispose = function() { + var result = native_.callSync('MLPipelineDispose', { id: this._id }); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineDisposeExceptions, + AbortError + ); + } +}; //Pipeline::dispose() end //Pipeline::getNodeInfo() begin diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 0576dac..1741550 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -41,7 +41,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { // Pipeline API begin REGISTER_METHOD(MLPipelineManagerCreatePipeline); REGISTER_METHOD(MLPipelineGetState); - + REGISTER_METHOD(MLPipelineDispose); // Pipeline API end #undef REGISTER_METHOD @@ -145,7 +145,25 @@ void MlInstance::MLPipelineGetState(const picojson::value& args, picojson::objec // Pipeline::stop() end // Pipeline::dispose() begin +void MlInstance::MLPipelineDispose(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; + } + + auto id = static_cast(args.get(kId).get()); + auto ret = pipeline_manager_.DisposePipeline(id); + if (!ret) { + ReportError(ret, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::dispose() end // Pipeline::getNodeInfo() begin @@ -203,7 +221,6 @@ void MlInstance::MLPipelineGetState(const picojson::value& args, picojson::objec // Valve::setOpen() begin // Valve::setOpen() end - // Pipeline API end } // namespace ml diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 7bb28f4..975fd7a 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -60,7 +60,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::stop() end // Pipeline::dispose() begin - + void MLPipelineDispose(const picojson::value& args, picojson::object& out); // Pipeline::dispose() end // Pipeline::getNodeInfo() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 6faec44..440d773 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -112,6 +112,11 @@ PlatformResult Pipeline::CreatePipeline(int id, const std::string& definition, Pipeline::~Pipeline() { ScopeLogger("Destroying pipeline: [%d]", id_); + if (!pipeline_) { + LoggerD("pipeline_ has already been destroyed"); + return; + } + auto ret = ml_pipeline_destroy(pipeline_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); @@ -158,7 +163,20 @@ PlatformResult Pipeline::GetState(std::string* out) { // Pipeline::stop() end // Pipeline::dispose() begin +PlatformResult Pipeline::Dispose() { + ScopeLogger("id_: [%d]", id_); + + auto ret = ml_pipeline_destroy(pipeline_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not dispose the pipeline"); + } + LoggerD("ml_pipeline_destroy() succeeded"); + pipeline_ = nullptr; + + return PlatformResult{}; +} // Pipeline::dispose() end // Pipeline::getNodeInfo() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index c29f244..92e2fa9 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -64,7 +64,7 @@ class Pipeline { // Pipeline::stop() end // Pipeline::dispose() begin - + PlatformResult Dispose(); // Pipeline::dispose() end // Pipeline::getNodeInfo() begin diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index 2d4781c..553770a 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -82,7 +82,27 @@ PlatformResult PipelineManager::GetPipelineState(int id, std::string* out) { // Pipeline::stop() end // Pipeline::dispose() begin +PlatformResult PipelineManager::DisposePipeline(int id) { + ScopeLogger("id: [%d]", id); + + auto pipeline_it = pipelines_.find(id); + if (pipelines_.end() == pipeline_it) { + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + /* + * Native ml_pipeline_destroy() may fail (I've checked its implementation), + * so we shouldn't just call pipelines_.erase(id) and let the ~Pipeline() + * destroy the pipeline, but only call pipelines_.erase(id) when + * pipeline->Dispose() succeeds. + */ + auto ret = pipeline_it->second->Dispose(); + if (ret) { + pipelines_.erase(id); + } + + return ret; +} // Pipeline::dispose() end // Pipeline::getNodeInfo() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index f3e0293..f5d0af3 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -56,7 +56,7 @@ class PipelineManager { // Pipeline::stop() end // Pipeline::dispose() begin - + PlatformResult DisposePipeline(int id); // Pipeline::dispose() end // Pipeline::getNodeInfo() begin -- 2.7.4 From 8eb1cc23dc863571f3519e4419283e2b1f423271 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Mon, 18 Jan 2021 14:01:19 +0100 Subject: [PATCH 10/16] [ML][pipeline] Prepare room for a bugfix Native handles to all pipeline elements (switches, node infos, etc.) have to be released BEFORE Pipeline::pipeline_ handle. Pipeline::Dispose() will release them in proper order and from now on will be called from ~Pipeline() to not repeat the error prone release logic. [Verification] Code tested with below snippets in Chrome DevTools works fine. var pipeline = tizen.ml.pipeline.createPipeline('videotestsrc ! tizenwlsink', function(state) {console.log(state);}) // test screen appears pipeline.dispose() // no errors, test screen disappear; // DLOG message about successful disposal // no crash; DLOG message tells that pipeline_ has been destroyed Change-Id: Ibe8b1260bc7bf057fed375ac579b87fce59d8caf Signed-off-by: Pawel Wasowski --- src/ml/ml_pipeline.cc | 17 ++++++++++++----- src/ml/ml_pipeline.h | 5 +++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 440d773..63b6fbf 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -117,11 +117,7 @@ Pipeline::~Pipeline() { return; } - auto ret = ml_pipeline_destroy(pipeline_); - if (ML_ERROR_NONE != ret) { - LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); - } - LoggerD("ml_pipeline_destroy() succeeded"); + Dispose(); } void Pipeline::PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data) { @@ -166,6 +162,17 @@ PlatformResult Pipeline::GetState(std::string* out) { PlatformResult Pipeline::Dispose() { ScopeLogger("id_: [%d]", id_); + /* + * TODO in future commits: + * + * Release all nodes belonging to this pipeline and + * cached in this object in containers like + * switches_, node_infos_, etc. + * + * They have to be released HERE (i.e. BEFORE releasing pipeline_). + * If they're released after pipeline_, the app may crash. + */ + auto ret = ml_pipeline_destroy(pipeline_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 92e2fa9..5fd19aa 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -125,6 +125,11 @@ class Pipeline { private: Pipeline(int id, const std::string& state_change_listener_name, common::Instance* instance_ptr); + /* ######### VERY IMPORTANT ######### + * All nnstreamer handles to nodes belonging to this Pipeline + * object have to be released in Dispose(), before calling + * ml_pipeline_destroy(pipeline_) (otherwise, the app may crash). + */ const int id_; ml_pipeline_h pipeline_; const std::string state_change_listener_name_; -- 2.7.4 From 16a21310c7b8048d21f014173f13a62983ae6d2a Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Wed, 23 Dec 2020 08:54:06 +0100 Subject: [PATCH 11/16] [ML][common] Add tizen.ml.checkNNFWAvailability method ACR: TWDAPI-273 Test code: var HWType = ["ANY", "AUTO", "CPU", "CPU_NEON", "CPU_SIMD", "GPU", "NPU", "NPU_EDGE_TPU", "NPU_MOVIDIUS", "NPU_SR", "NPU_VIVANTE"]; var NNFWType = ["ANY", "ARM_NN", "CUSTOM_FILTER", "EDGE_TPU", "MVNC", "NNFW", "OPEN_VINO", "SNPE", "TENSORFLOW", "TENSORFLOW_LITE", "VIVANTE"]; HWType.forEach(hw => { NNFWType.forEach(nnfw => { console.log(nnfw + ", " + hw + ": " + tizen.ml.checkNNFWAvailability(nnfw, hw)) }); }); [Verificaion] Tested in Google Chrome Dev Console Change-Id: I2ac7752f410a70e98d8c0cd387ac5dfcabdbef88 Signed-off-by: Rafal Walczyna --- src/ml/js/ml_common.js | 2 +- src/ml/js/ml_manager.js | 54 +++++++++++++++++++++++++++++++++++++++++++++- src/ml/ml_instance.cc | 27 +++++++++++++++++++++++ src/ml/ml_instance.h | 1 + src/ml/ml_utils.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- src/ml/ml_utils.h | 12 +++++++++++ 6 files changed, 148 insertions(+), 5 deletions(-) diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index c8bc981..415ff53 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -70,7 +70,7 @@ var TensorsData = function() { throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); } }, - tensorsInfo : { + tensorsInfo: { enumerable: true, get: function() { throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); diff --git a/src/ml/js/ml_manager.js b/src/ml/js/ml_manager.js index 549bcdd..69d96a3 100755 --- a/src/ml/js/ml_manager.js +++ b/src/ml/js/ml_manager.js @@ -20,8 +20,60 @@ MachineLearningManager.prototype.single = new MachineLearningSingle(); MachineLearningManager.prototype.pipeline = new MachineLearningPipeline(); +var NNFWType = { + ANY: 'ANY', + ARM_NN: 'ARM_NN', + CUSTOM_FILTER: 'CUSTOM_FILTER', + EDGE_TPU: 'EDGE_TPU', + MVNC: 'MVNC', + NNFW: 'NNFW', + OPEN_VINO: 'OPEN_VINO', + SNPE: 'SNPE', + TENSORFLOW: 'TENSORFLOW', + TENSORFLOW_LITE: 'TENSORFLOW_LITE', + VIVANTE: 'VIVANTE' +}; + +var HWType = { + ANY: 'ANY', + AUTO: 'AUTO', + CPU: 'CPU', + CPU_NEON: 'CPU_NEON', + CPU_SIMD: 'CPU_SIMD', + GPU: 'GPU', + NPU: 'NPU', + NPU_EDGE_TPU: 'NPU_EDGE_TPU', + NPU_MOVIDIUS: 'NPU_MOVIDIUS', + NPU_SR: 'NPU_SR', + NPU_VIVANTE: 'NPU_VIVANTE' +}; + MachineLearningManager.prototype.checkNNFWAvailability = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'nnfw', + type: types_.ENUM, + values: Object.values(NNFWType), + optional: false + }, + { + name: 'hw', + type: types_.ENUM, + values: Object.values(HWType), + optional: false + } + ]); + var callArgs = { + nnfw: args.nnfw, + hw: args.hw + }; + + var result = native_.callSync('MLCheckNNFWAvailability', callArgs); + + if (native_.isFailure(result)) { + return false; + } + return native_.getResultObject(result); }; exports = new MachineLearningManager(); diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 1741550..3aaad4c 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -15,15 +15,28 @@ */ #include "ml_instance.h" +#include "ml_utils.h" #include "common/logger.h" #include "common/picojson.h" +#include "common/platform_result.h" namespace extension { namespace ml { +namespace { +const std::string kNnfw = "nnfw"; +const std::string kHw = "hw"; +} + using namespace common; +#define CHECK_EXIST(args, name, out) \ + if (!args.contains(name)) { \ + LogAndReportError(TypeMismatchException(std::string(name) + " is required argument"), out); \ + return; \ + } + MlInstance::MlInstance() : pipeline_manager_{this} { ScopeLogger(); using namespace std::placeholders; @@ -31,6 +44,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { #define REGISTER_METHOD(M) RegisterSyncHandler(#M, std::bind(&MlInstance::M, this, _1, _2)) // Common ML API begin + REGISTER_METHOD(MLCheckNNFWAvailability); // Common ML API end @@ -52,7 +66,18 @@ MlInstance::~MlInstance() { } // Common ML API begin +void MlInstance::MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_EXIST(args, kNnfw, out) + CHECK_EXIST(args, kHw, out) + + std::string nnfw = args.get(kNnfw).get(); + std::string hw = args.get(kHw).get(); + bool availability_val = util::CheckNNFWAvailability(nnfw, hw); + picojson::value available = picojson::value{availability_val}; + ReportSuccess(available, out); +} // Common ML API end // Single API begin @@ -223,5 +248,7 @@ void MlInstance::MLPipelineDispose(const picojson::value& args, picojson::object // Valve::setOpen() end // Pipeline API end +#undef CHECK_EXIST + } // namespace ml } // namespace extension diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 975fd7a..7d455f8 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -33,6 +33,7 @@ class MlInstance : public common::ParsedInstance { private: // Common ML API begin + void MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out); // Common ML API end diff --git a/src/ml/ml_utils.cc b/src/ml/ml_utils.cc index 7babe96..d29605d 100644 --- a/src/ml/ml_utils.cc +++ b/src/ml/ml_utils.cc @@ -16,12 +16,38 @@ #include -#include "ml_utils.h" - #include "common/logger.h" +#include "ml_utils.h" namespace extension { namespace ml { + +namespace types { +const PlatformEnum HWTypeEnum{{"ANY", ML_NNFW_HW_ANY}, + {"AUTO", ML_NNFW_HW_AUTO}, + {"CPU", ML_NNFW_HW_CPU}, + {"CPU_NEON", ML_NNFW_HW_CPU_NEON}, + {"CPU_SIMD", ML_NNFW_HW_CPU_SIMD}, + {"GPU", ML_NNFW_HW_GPU}, + {"NPU", ML_NNFW_HW_NPU}, + {"NPU_EDGE_TPU", ML_NNFW_HW_NPU_EDGE_TPU}, + {"NPU_MOVIDIUS", ML_NNFW_HW_NPU_MOVIDIUS}, + {"NPU_SR", ML_NNFW_HW_NPU_SR}, + {"NPU_VIVANTE", ML_NNFW_HW_NPU_VIVANTE}}; + +const PlatformEnum NNFWTypeEnum{{"ANY", ML_NNFW_TYPE_ANY}, + {"ARM_NN", ML_NNFW_TYPE_ARMNN}, + {"CUSTOM_FILTER", ML_NNFW_TYPE_CUSTOM_FILTER}, + {"EDGE_TPU", ML_NNFW_TYPE_EDGE_TPU}, + {"MVNC", ML_NNFW_TYPE_MVNC}, + {"NNFW", ML_NNFW_TYPE_NNFW}, + {"OPEN_VINO", ML_NNFW_TYPE_OPENVINO}, + {"SNPE", ML_NNFW_TYPE_SNPE}, + {"TENSORFLOW", ML_NNFW_TYPE_TENSORFLOW}, + {"TENSORFLOW_LITE", ML_NNFW_TYPE_TENSORFLOW_LITE}, + {"VIVANTE", ML_NNFW_TYPE_VIVANTE}}; +} // types + namespace util { PlatformResult ToPlatformResult(int ml_error_code, const std::string& error_message_beginning) { @@ -53,7 +79,32 @@ PlatformResult ToPlatformResult(int ml_error_code, const std::string& error_mess } } -using namespace common; +bool CheckNNFWAvailability(const std::string& nnfw, const std::string& hw) { + ScopeLogger(); + ml_nnfw_type_e nnfw_e = ML_NNFW_TYPE_ANY; + ml_nnfw_hw_e hw_e = ML_NNFW_HW_ANY; + + PlatformResult result = types::NNFWTypeEnum.getValue(nnfw, &nnfw_e); + if (!result) { + LoggerE("NNFWTypeEnum.getValue() failed, error: %s", result.message().c_str()); + return false; + } + result = types::HWTypeEnum.getValue(hw, &hw_e); + if (!result) { + LoggerE("HWTypeEnum.getValue() failed, error: %s", result.message().c_str()); + return false; + } + bool available = false; + int ret = ml_check_nnfw_availability(nnfw_e, hw_e, &available); + + if (ML_ERROR_NONE != ret) { + LoggerE("ml_check_nnfw_availability failed: %d (%s)", ret, get_error_message(ret)); + return false; + } + + LoggerD("ml_check_nnfw_availability: %s", available ? "true" : "false"); + return available; +} } // util } // ml diff --git a/src/ml/ml_utils.h b/src/ml/ml_utils.h index 725c7d9..bc476b1 100644 --- a/src/ml/ml_utils.h +++ b/src/ml/ml_utils.h @@ -20,17 +20,29 @@ #include #include "common/picojson.h" +#include "common/platform_enum.h" #include "common/platform_result.h" +using common::PlatformEnum; using common::PlatformResult; using common::ErrorCode; namespace extension { namespace ml { + +namespace types { + +extern const PlatformEnum HWTypeEnum; +extern const PlatformEnum NNFWTypeEnum; + +} // types + namespace util { PlatformResult ToPlatformResult(int ml_error_code, const std::string& error_message); +bool CheckNNFWAvailability(const std::string& nnfw, const std::string& hw); + } // util } // ml } // extension -- 2.7.4 From 19ac4ad30701963f6e51fff59c8554b19307726d Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Mon, 11 Jan 2021 08:29:29 +0100 Subject: [PATCH 12/16] [ML][Pipeline] Implement Start and Stop method. ACR: TWDAPI-274 [Verification] Code compiles without error. var pipeline = tizen.ml.pipeline.createPipeline("videotestsrc! tizenwlsink"); pipeline.start() // pipeline.state = "PLAYING" pipeline.stop() // pipeline.state = "PAUSED" Change-Id: I529c47fd349741d3e11b0b57e265d3a9a930f652 Signed-off-by: Lukasz Bardeli --- src/ml/js/ml_pipeline.js | 27 +++++++++++++++++++++++++++ src/ml/ml_instance.cc | 39 +++++++++++++++++++++++++++++++++++++++ src/ml/ml_instance.h | 4 ++-- src/ml/ml_pipeline.cc | 18 ++++++++++++++++++ src/ml/ml_pipeline.h | 6 +++--- src/ml/ml_pipeline_manager.cc | 22 ++++++++++++++++++++++ src/ml/ml_pipeline_manager.h | 6 +++--- 7 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index e9debd3..17dba5e 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -114,11 +114,38 @@ var Pipeline = function(id) { //Pipeline::state end //Pipeline::start() begin +var ValidPipelineStartStopExceptions = ['NotFoundError', 'NotSupportedError', 'AbortError']; +Pipeline.prototype.start = function() { + var nativeArgs = { + id: this._id + }; + var result = native_.callSync('MLPipelineStart', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineStartStopExceptions, + AbortError + ); + } +}; //Pipeline::start() end //Pipeline::stop() begin +Pipeline.prototype.stop = function() { + var nativeArgs = { + id: this._id + }; + var result = native_.callSync('MLPipelineStop', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineStartStopExceptions, + AbortError + ); + } +}; //Pipeline::stop() end //Pipeline::dispose() begin diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 1741550..3a0cd4d 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -42,6 +42,8 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLPipelineManagerCreatePipeline); REGISTER_METHOD(MLPipelineGetState); REGISTER_METHOD(MLPipelineDispose); + REGISTER_METHOD(MLPipelineStart); + REGISTER_METHOD(MLPipelineStop); // Pipeline API end #undef REGISTER_METHOD @@ -137,11 +139,47 @@ void MlInstance::MLPipelineGetState(const picojson::value& args, picojson::objec // Pipeline::state end // Pipeline::start() begin +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; + } + auto id = static_cast(args.get(kId).get()); + PlatformResult result = pipeline_manager_.Start(id); + + if (!result) { + ReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::start() end // Pipeline::stop() begin +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; + } + auto id = static_cast(args.get(kId).get()); + + PlatformResult result = pipeline_manager_.Stop(id); + + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::stop() end // Pipeline::dispose() begin @@ -221,6 +259,7 @@ void MlInstance::MLPipelineDispose(const picojson::value& args, picojson::object // Valve::setOpen() begin // Valve::setOpen() end + // Pipeline API end } // namespace ml diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 975fd7a..df6e214 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -52,11 +52,11 @@ class MlInstance : public common::ParsedInstance { // Pipeline::state end // Pipeline::start() begin - + void MLPipelineStart(const picojson::value& args, picojson::object& out); // Pipeline::start() end // Pipeline::stop() begin - + void MLPipelineStop(const picojson::value& args, picojson::object& out); // Pipeline::stop() end // Pipeline::dispose() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 63b6fbf..10930cf 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -151,11 +151,29 @@ PlatformResult Pipeline::GetState(std::string* out) { // Pipeline::state end // Pipeline::start() begin +PlatformResult Pipeline::Start() { + ScopeLogger("id_: [%d]", id_); + auto ret = ml_pipeline_start(pipeline_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_start() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not start pipeline"); + } + return PlatformResult{}; +} // Pipeline::start() end // Pipeline::stop() begin +PlatformResult Pipeline::Stop() { + ScopeLogger("id_: [%d]", id_); + auto ret = ml_pipeline_stop(pipeline_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_stop() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not stop pipeline"); + } + return PlatformResult{}; +} // Pipeline::stop() end // Pipeline::dispose() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 5fd19aa..42287f8 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -56,11 +56,11 @@ class Pipeline { // Pipeline::state end // Pipeline::start() begin - + PlatformResult Start(); // Pipeline::start() end // Pipeline::stop() begin - + PlatformResult Stop(); // Pipeline::stop() end // Pipeline::dispose() begin @@ -141,4 +141,4 @@ class Pipeline { } // namespace ml } // namespace extension -#endif // ML_ML_PIPELINE_H_ \ No newline at end of file +#endif // ML_ML_PIPELINE_H_ diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index 553770a..3d57861 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -74,11 +74,33 @@ PlatformResult PipelineManager::GetPipelineState(int id, std::string* out) { // Pipeline::state end // Pipeline::start() begin +PlatformResult PipelineManager::Start(int id) { + ScopeLogger("id: [%d]", id); + 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"}; + } + + auto ret = pipeline_it->second->Start(); + return ret; +} // Pipeline::start() end // Pipeline::stop() begin +PlatformResult PipelineManager::Stop(int id) { + ScopeLogger("id: [%d]", id); + 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"}; + } + + auto ret = pipeline_it->second->Stop(); + return ret; +} // Pipeline::stop() end // Pipeline::dispose() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index f5d0af3..300aa31 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -48,11 +48,11 @@ class PipelineManager { // Pipeline::state end // Pipeline::start() begin - + PlatformResult Start(int id); // Pipeline::start() end // Pipeline::stop() begin - + PlatformResult Stop(int id); // Pipeline::stop() end // Pipeline::dispose() begin @@ -122,4 +122,4 @@ class PipelineManager { } // namespace ml } // namespace extension -#endif // ML_ML_PIPELINE_MANAGER_H_ \ No newline at end of file +#endif // ML_ML_PIPELINE_MANAGER_H_ -- 2.7.4 From 29885d6544861f5067fcfc31f08d1123822249f7 Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Tue, 12 Jan 2021 10:24:45 +0100 Subject: [PATCH 13/16] [ML][Pipeline] Implement getNodeInfo ACR: TWDAPI-274 [Verification] Code compiles without error. Tested in chrome console var pipeline = 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 = pipeline.getNodeInfo("demux") Change-Id: I503f0a2a52b151ac676a64e2ad888f45abc51170 Signed-off-by: Lukasz Bardeli --- src/ml/js/ml_pipeline.js | 43 +++++++++++++++++++++++++++- src/ml/ml.gyp | 2 ++ src/ml/ml_instance.cc | 28 ++++++++++++++++++ src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 21 ++++++++++++++ src/ml/ml_pipeline.h | 6 +++- src/ml/ml_pipeline_manager.cc | 11 ++++++++ src/ml/ml_pipeline_manager.h | 2 +- src/ml/ml_pipeline_nodeinfo.cc | 64 ++++++++++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline_nodeinfo.h | 53 ++++++++++++++++++++++++++++++++++ 10 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 src/ml/ml_pipeline_nodeinfo.cc create mode 100644 src/ml/ml_pipeline_nodeinfo.h diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index 17dba5e..df2913a 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -114,7 +114,11 @@ var Pipeline = function(id) { //Pipeline::state end //Pipeline::start() begin -var ValidPipelineStartStopExceptions = ['NotFoundError', 'NotSupportedError', 'AbortError']; +var ValidPipelineStartStopExceptions = [ + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; Pipeline.prototype.start = function() { var nativeArgs = { id: this._id @@ -163,7 +167,44 @@ Pipeline.prototype.dispose = function() { //Pipeline::dispose() end //Pipeline::getNodeInfo() begin +var NodeInfo = function(name, pipeline_id) { + Object.defineProperties(this, { + name: { enumerable: true, writable: false, value: name }, + _pipeline_id: { value: pipeline_id } + }); +}; + +var ValidPipelineGetNodeInfoExceptions = [ + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; + +Pipeline.prototype.getNodeInfo = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + } + ]); + + var nativeArgs = { + id: this._id, + name: args.name + }; + + var result = native_.callSync('MLPipelineGetNodeInfo', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineGetNodeInfoExceptions, + AbortError + ); + } + return new NodeInfo(args.name, this._id); +}; //Pipeline::getNodeInfo() end //Pipeline::getSource() begin diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index 65a987d..c0ab826 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -19,6 +19,8 @@ 'ml_pipeline.h', 'ml_pipeline_manager.cc', 'ml_pipeline_manager.h', + 'ml_pipeline_nodeinfo.cc', + 'ml_pipeline_nodeinfo.h', 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 3a0cd4d..7a69c2b 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -44,6 +44,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLPipelineDispose); REGISTER_METHOD(MLPipelineStart); REGISTER_METHOD(MLPipelineStop); + REGISTER_METHOD(MLPipelineGetNodeInfo); // Pipeline API end #undef REGISTER_METHOD @@ -66,6 +67,7 @@ MlInstance::~MlInstance() { namespace { const std::string kId = "id"; +const std::string kName = "name"; const std::string kDefinition = "definition"; const std::string kPipelineStateChangeListenerName = "listenerName"; @@ -205,7 +207,33 @@ void MlInstance::MLPipelineDispose(const picojson::value& args, picojson::object // Pipeline::dispose() end // Pipeline::getNodeInfo() begin +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; + } + auto name = args.get(kName).get(); + auto id = static_cast(args.get(kId).get()); + + PlatformResult result = pipeline_manager_.GetNodeInfo(id, name); + + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Pipeline::getNodeInfo() end // Pipeline::getSource() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index df6e214..9b1f430 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -64,7 +64,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::dispose() end // Pipeline::getNodeInfo() begin - + void MLPipelineGetNodeInfo(const picojson::value& args, picojson::object& out); // Pipeline::getNodeInfo() end // Pipeline::getSource() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index 10930cf..c843df3 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -191,6 +191,8 @@ PlatformResult Pipeline::Dispose() { * If they're released after pipeline_, the app may crash. */ + node_info_.clear(); + auto ret = ml_pipeline_destroy(pipeline_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret)); @@ -205,7 +207,26 @@ PlatformResult Pipeline::Dispose() { // Pipeline::dispose() end // Pipeline::getNodeInfo() begin +PlatformResult Pipeline::GetNodeInfo(std::string& name) { + ScopeLogger("id_: [%d], name: [%s]", id_, name.c_str()); + + auto nodeinfo_it = node_info_.find(name); + if (node_info_.end() != nodeinfo_it) { + LoggerD("NodeInfo [%s] found", name.c_str()); + return PlatformResult{}; + } + std::unique_ptr node_info_ptr; + auto ret = NodeInfo::CreateNodeInfo(pipeline_, name, &node_info_ptr); + + if (!ret) { + return ret; + } + + node_info_.insert({name, std::move(node_info_ptr)}); + + return PlatformResult{}; +} // Pipeline::getNodeInfo() end // Pipeline::getSource() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 42287f8..80c859b 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -25,8 +25,10 @@ #include "common/extension.h" #include "common/picojson.h" #include "common/platform_result.h" +#include "ml_pipeline_nodeinfo.h" using common::PlatformResult; +using extension::ml::pipeline::NodeInfo; namespace extension { namespace ml { @@ -68,7 +70,7 @@ class Pipeline { // Pipeline::dispose() end // Pipeline::getNodeInfo() begin - + PlatformResult GetNodeInfo(std::string& name); // Pipeline::getNodeInfo() end // Pipeline::getSource() begin @@ -135,6 +137,8 @@ class Pipeline { const std::string state_change_listener_name_; common::Instance* instance_ptr_; + std::map> node_info_; + 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 3d57861..cadb4d4 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -128,7 +128,18 @@ PlatformResult PipelineManager::DisposePipeline(int id) { // Pipeline::dispose() end // Pipeline::getNodeInfo() begin +PlatformResult PipelineManager::GetNodeInfo(int id, std::string& name) { + ScopeLogger("id: [%d], name [%s]", id, name.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"}; + } + + auto ret = pipeline_it->second->GetNodeInfo(name); + return ret; +} // Pipeline::getNodeInfo() end // Pipeline::getSource() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 300aa31..63ee5aa 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -60,7 +60,7 @@ class PipelineManager { // Pipeline::dispose() end // Pipeline::getNodeInfo() begin - + PlatformResult GetNodeInfo(int id, std::string& name); // Pipeline::getNodeInfo() end // Pipeline::getSource() begin diff --git a/src/ml/ml_pipeline_nodeinfo.cc b/src/ml/ml_pipeline_nodeinfo.cc new file mode 100644 index 0000000..c1e7a34 --- /dev/null +++ b/src/ml/ml_pipeline_nodeinfo.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 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_pipeline_nodeinfo.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { +namespace pipeline { + +PlatformResult NodeInfo::CreateNodeInfo(ml_pipeline_h pipeline, const std::string& name, + std::unique_ptr* out) { + std::unique_ptr nodeinfo_ptr{new (std::nothrow) NodeInfo{name}}; + if (!nodeinfo_ptr) { + return LogAndCreateResult(ErrorCode::ABORT_ERR, "An unknown occurred.", + ("Could not allocate memory for NodeInfo")); + } + auto ret = ml_pipeline_element_get_handle(pipeline, name.c_str(), &nodeinfo_ptr->node_info_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_get_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get NodeInfo"); + } + + *out = std::move(nodeinfo_ptr); + return PlatformResult{}; +} + +NodeInfo::NodeInfo(const std::string& name) : name_{name} { + ScopeLogger("name: [%s], ", name.c_str()); +} + +NodeInfo::~NodeInfo() { + ScopeLogger("name: [%s], handle: [%p]", name_.c_str(), node_info_); + + auto ret = ml_pipeline_element_release_handle(node_info_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_element_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_element_release_handle() succeeded"); + } +} + +} // namespace pipeline +} // namespace ml +} // namespace extension \ No newline at end of file diff --git a/src/ml/ml_pipeline_nodeinfo.h b/src/ml/ml_pipeline_nodeinfo.h new file mode 100644 index 0000000..4140025 --- /dev/null +++ b/src/ml/ml_pipeline_nodeinfo.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 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_NODEINFO_H_ +#define ML_ML_PIPELINE_NODEINFO_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { +namespace pipeline { + +class NodeInfo { + public: + NodeInfo() = delete; + NodeInfo(const NodeInfo&) = delete; + NodeInfo& operator=(const NodeInfo&) = delete; + static PlatformResult CreateNodeInfo(ml_pipeline_h pipeline, const std::string& name, + std::unique_ptr* out); + + ~NodeInfo(); + + private: + NodeInfo(const std::string& name); + const std::string name_; + ml_pipeline_element_h node_info_; +}; + +} // namespace pipeline +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_NODEINFO_H_ \ No newline at end of file -- 2.7.4 From ee3d5a03fee9b4234e707bbb15dc3cd824704bbb Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 12 Jan 2021 16:38:43 +0100 Subject: [PATCH 14/16] [ML][pipeline] Implement Pipeline::getSwitch() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ACR: TWDAPI-274 [Verification] Code tested in Chrome DevTools with below snippets works fine var pipeline_def = "videotestsrc is-live=true" + " ! videoconvert" + " ! tensor_converter" + " ! output-selector name=outs outs.src_0" + " ! tensor_sink name=sink0 async=false outs.src_1" + " ! tensor_sink name=sink1 async=false" var pipeline = tizen.ml.pipeline.createPipeline(pipeline_def, function(state) {console.log(state);}) pipeline.getSwitch('outs') // Switch {name: "outs", type: "OUTPUT_SELECTOR", _pipeline_id: 3} pipeline.getSwitch('non existent switch') // VM31:1 Uncaught WebAPIException {code: 0, name: "InvalidValuesError" Change-Id: Ia7d6838b5e49072c35f0b796151c436d4a3b60e1 Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 45 +++++++++++++++++++++ src/ml/ml.gyp | 2 + src/ml/ml_instance.cc | 28 +++++++++++++ src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 19 +++++++++ src/ml/ml_pipeline.h | 23 +++++++---- src/ml/ml_pipeline_manager.cc | 12 ++++++ src/ml/ml_pipeline_manager.h | 2 +- src/ml/ml_pipeline_switch.cc | 91 +++++++++++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline_switch.h | 56 ++++++++++++++++++++++++++ 10 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 src/ml/ml_pipeline_switch.cc create mode 100644 src/ml/ml_pipeline_switch.h diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index df2913a..2cfb8be 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -212,7 +212,52 @@ Pipeline.prototype.getNodeInfo = function() { //Pipeline::getSource() end //Pipeline::getSwitch() begin +function Switch(name, type, pipeline_id) { + Object.defineProperties(this, { + name: { + enumerable: true, + value: name + }, + type: { + enumerable: true, + value: type + }, + _pipeline_id: { + value: pipeline_id + } + }); +} +var ValidPipelineGetSwitchExceptions = [ + 'InvalidStateError', + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; +Pipeline.prototype.getSwitch = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + } + ]); + + var nativeArgs = { + name: args.name, + id: this._id + }; + var result = native_.callSync('MLPipelineGetSwitch', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineGetSwitchExceptions, + AbortError + ); + } + + return new Switch(nativeArgs.name, result.type, this._id); +}; //Pipeline::getSwitch() end //Pipeline::getValve() begin diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index c0ab826..1c60e04 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -21,6 +21,8 @@ 'ml_pipeline_manager.h', 'ml_pipeline_nodeinfo.cc', 'ml_pipeline_nodeinfo.h', + 'ml_pipeline_switch.cc', + 'ml_pipeline_switch.h', 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index e9445ad..853dab4 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -59,6 +59,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLPipelineStart); REGISTER_METHOD(MLPipelineStop); REGISTER_METHOD(MLPipelineGetNodeInfo); + REGISTER_METHOD(MLPipelineGetSwitch); // Pipeline API end #undef REGISTER_METHOD @@ -266,7 +267,34 @@ void MlInstance::MLPipelineGetNodeInfo(const picojson::value& args, picojson::ob // Pipeline::getSource() end // Pipeline::getSwitch() begin +void MlInstance::MLPipelineGetSwitch(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; + } + + auto name = args.get(kName).get(); + auto pipeline_id = args.get(kId).get(); + std::string type; + + auto ret = pipeline_manager_.GetSwitch(name, pipeline_id, &type); + if (!ret) { + LogAndReportError(ret, &out); + return; + } + + out["type"] = picojson::value{type}; + ReportSuccess(out); +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 47d9567..acb013c 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -73,7 +73,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + void MLPipelineGetSwitch(const picojson::value& args, picojson::object& out); // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index c843df3..de5edb1 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -190,6 +190,7 @@ PlatformResult Pipeline::Dispose() { * They have to be released HERE (i.e. BEFORE releasing pipeline_). * If they're released after pipeline_, the app may crash. */ + switches_.clear(); node_info_.clear(); @@ -234,7 +235,25 @@ PlatformResult Pipeline::GetNodeInfo(std::string& name) { // Pipeline::getSource() end // Pipeline::getSwitch() begin +PlatformResult Pipeline::GetSwitch(const std::string& name, std::string* type) { + ScopeLogger("id: [%d], name: [%s]", id_, name.c_str()); + auto switch_it = switches_.find(name); + if (switches_.end() != switch_it) { + LoggerD("Switch [%s] found", name.c_str()); + *type = switch_it->second->GetType(); + return PlatformResult{}; + } + LoggerD("Switch [%s] not found", name.c_str()); + + std::unique_ptr switch_ptr; + auto ret = Switch::CreateSwitch(name, pipeline_, &switch_ptr); + if (ret) { + *type = switch_ptr->GetType(); + switches_.insert({name, std::move(switch_ptr)}); + } + return ret; +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 80c859b..9d3df8c 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -26,9 +27,10 @@ #include "common/picojson.h" #include "common/platform_result.h" #include "ml_pipeline_nodeinfo.h" +#include "ml_pipeline_switch.h" using common::PlatformResult; -using extension::ml::pipeline::NodeInfo; +using namespace extension::ml::pipeline; namespace extension { namespace ml { @@ -46,7 +48,6 @@ class Pipeline { common::Instance* instance_ptr, std::unique_ptr* out); // PipelineManager::createPipeline() end - Pipeline() = delete; Pipeline(const Pipeline&) = delete; Pipeline& operator=(const Pipeline&) = delete; @@ -78,7 +79,7 @@ class Pipeline { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + PlatformResult GetSwitch(const std::string& name, std::string* type); // Pipeline::getSwitch() end // Pipeline::getValve() begin @@ -127,16 +128,24 @@ class Pipeline { private: Pipeline(int id, const std::string& state_change_listener_name, common::Instance* instance_ptr); + const int id_; + ml_pipeline_h pipeline_; + const std::string state_change_listener_name_; + common::Instance* instance_ptr_; + /* ######### VERY IMPORTANT ######### * All nnstreamer handles to nodes belonging to this Pipeline * object have to be released in Dispose(), before calling * ml_pipeline_destroy(pipeline_) (otherwise, the app may crash). */ - const int id_; - ml_pipeline_h pipeline_; - const std::string state_change_listener_name_; - common::Instance* instance_ptr_; + /* + * 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 + * retrieval. + */ + std::unordered_map> switches_; std::map> node_info_; 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 cadb4d4..20bae15 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -16,6 +16,7 @@ #include "ml_pipeline_manager.h" #include "common/tools.h" +#include "ml_pipeline_switch.h" using common::PlatformResult; using common::ErrorCode; @@ -147,7 +148,18 @@ PlatformResult PipelineManager::GetNodeInfo(int id, std::string& name) { // Pipeline::getSource() end // Pipeline::getSwitch() begin +PlatformResult PipelineManager::GetSwitch(const std::string& name, int pipeline_id, + std::string* type) { + 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->GetSwitch(name, type); +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 63ee5aa..f031fc8 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -68,7 +68,7 @@ class PipelineManager { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + PlatformResult GetSwitch(const std::string& name, int pipeline_id, std::string* type); // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline_switch.cc b/src/ml/ml_pipeline_switch.cc new file mode 100644 index 0000000..43a8220 --- /dev/null +++ b/src/ml/ml_pipeline_switch.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 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_switch.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace { + +std::string TypeToString(ml_pipeline_switch_e type) { + ScopeLogger("type: [%d]", type); + + std::string type_str = + (ML_PIPELINE_SWITCH_INPUT_SELECTOR == type) ? "INPUT_SELECTOR" : "OUTPUT_SELECTOR"; + LoggerD("type_str: [%s]", type_str.c_str()); + return type_str; +} + +} // namespace + +namespace extension { +namespace ml { +namespace pipeline { + +PlatformResult Switch::CreateSwitch(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out) { + ScopeLogger("name: [%s], pipeline: [%p]", name.c_str(), pipeline); + + ml_pipeline_switch_e type = ML_PIPELINE_SWITCH_INPUT_SELECTOR; + ml_pipeline_switch_h switch_handle = nullptr; + auto ret = ml_pipeline_switch_get_handle(pipeline, name.c_str(), &type, &switch_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_get_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get switch"); + } + LoggerD("ml_pipeline_switch_get_handle() succeeded"); + + out->reset(new (std::nothrow) Switch{name, TypeToString(type), switch_handle}); + if (!out) { + ret = ml_pipeline_switch_release_handle(switch_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_switch_release_handle() succeeded"); + } + return LogAndCreateResult(ErrorCode::ABORT_ERR, "Could not get the switch", + ("Could not allocate memory")); + } + + return PlatformResult{}; +} + +Switch::Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle) + : name_{name}, type_{type}, switch_{switch_handle} { + ScopeLogger("name: [%s], type: [%s], handle: [%p]", name.c_str(), type.c_str(), switch_handle); +} + +Switch::~Switch() { + ScopeLogger("name: [%s], type: [%s], handle: [%p]", name_.c_str(), type_.c_str(), switch_); + + auto ret = ml_pipeline_switch_release_handle(switch_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_switch_release_handle() succeeded"); + } +} + +std::string Switch::GetType() const { + ScopeLogger("type: [%s]", type_.c_str()); + return type_; +} + +} // namespace pipeline +} // namespace ml +} // namespace extension \ No newline at end of file diff --git a/src/ml/ml_pipeline_switch.h b/src/ml/ml_pipeline_switch.h new file mode 100644 index 0000000..3175387 --- /dev/null +++ b/src/ml/ml_pipeline_switch.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 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_SWITCH_H_ +#define ML_ML_PIPELINE_SWITCH_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { +namespace pipeline { + +class Switch { + public: + static PlatformResult CreateSwitch(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out); + + std::string GetType() const; + + ~Switch(); + + Switch(const Switch&) = delete; + Switch& operator=(const Switch&) = delete; + + private: + Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle); + const std::string name_; + const std::string type_; + const ml_pipeline_switch_h switch_; +}; + +} // namespace pipeline +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_SWITCH_H_ \ No newline at end of file -- 2.7.4 From 717764624f7a79a71066b67516642beed197a725 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Fri, 8 Jan 2021 16:39:37 +0100 Subject: [PATCH 15/16] [ML][Common] Add MLTensorsInfoManager ACR: TWDAPI-273 [Verification] Built successful Change-Id: I85a0fdcbcbc42ddcce406d5c6ae5a428536d4ce7 Signed-off-by: Rafal Walczyna --- src/ml/ml.gyp | 2 + src/ml/ml_instance.cc | 5 + src/ml/ml_instance.h | 4 + src/ml/ml_pipeline_nodeinfo.cc | 2 +- src/ml/ml_tensors_info_manager.cc | 224 ++++++++++++++++++++++++++++++++++++++ src/ml/ml_tensors_info_manager.h | 78 +++++++++++++ 6 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 src/ml/ml_tensors_info_manager.cc create mode 100644 src/ml/ml_tensors_info_manager.h diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index 1c60e04..c959f43 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -23,6 +23,8 @@ 'ml_pipeline_nodeinfo.h', 'ml_pipeline_switch.cc', 'ml_pipeline_switch.h', + 'ml_tensors_info_manager.cc', + 'ml_tensors_info_manager.h', 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 853dab4..97d1c37 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -17,6 +17,7 @@ #include "ml_instance.h" #include "ml_utils.h" +#include "common/converter.h" #include "common/logger.h" #include "common/picojson.h" #include "common/platform_result.h" @@ -69,6 +70,10 @@ MlInstance::~MlInstance() { ScopeLogger(); } +TensorsInfoManager& MlInstance::GetTensorsInfoManager() { + return tensors_info_manager_; +} + // Common ML API begin void MlInstance::MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index acb013c..ff2f74b 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -23,6 +23,8 @@ #include "nnstreamer/nnstreamer-single.h" #include "nnstreamer/nnstreamer.h" +#include "ml_tensors_info_manager.h" + namespace extension { namespace ml { @@ -30,11 +32,13 @@ class MlInstance : public common::ParsedInstance { public: MlInstance(); virtual ~MlInstance(); + TensorsInfoManager& GetTensorsInfoManager(); private: // Common ML API begin void MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out); + TensorsInfoManager tensors_info_manager_; // Common ML API end // Single API begin diff --git a/src/ml/ml_pipeline_nodeinfo.cc b/src/ml/ml_pipeline_nodeinfo.cc index c1e7a34..91fe836 100644 --- a/src/ml/ml_pipeline_nodeinfo.cc +++ b/src/ml/ml_pipeline_nodeinfo.cc @@ -51,7 +51,7 @@ NodeInfo::NodeInfo(const std::string& name) : name_{name} { NodeInfo::~NodeInfo() { ScopeLogger("name: [%s], handle: [%p]", name_.c_str(), node_info_); - auto ret = ml_pipeline_element_release_handle(node_info_); + auto ret = ml_pipeline_element_release_handle(node_info_); if (ML_ERROR_NONE != ret) { LoggerE("ml_pipeline_element_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); } else { diff --git a/src/ml/ml_tensors_info_manager.cc b/src/ml/ml_tensors_info_manager.cc new file mode 100644 index 0000000..ea80daf --- /dev/null +++ b/src/ml/ml_tensors_info_manager.cc @@ -0,0 +1,224 @@ +/* + * 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 "ml_tensors_info_manager.h" + +using common::ErrorCode; +using common::PlatformResult; + +namespace extension { +namespace ml { + +TensorsInfo::TensorsInfo(ml_tensors_info_h handle, int id) : handle_(handle), id_(id) { + ScopeLogger(); +} + +TensorsInfo::~TensorsInfo() { + ScopeLogger(); + this->NativeDestroy(); +} + +ml_tensors_info_h TensorsInfo::Handle() { + return this->handle_; +} + +int TensorsInfo::Id() { + return this->id_; +} + +PlatformResult TensorsInfo::NativeDestroy() { + ScopeLogger("id_: %d", id_); + int ret = ml_tensors_info_destroy(handle_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_destroy failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to destroy handle"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeGetCount(unsigned int* count) { + ScopeLogger("id_: %d", id_); + + int ret = ml_tensors_info_get_count(handle_, count); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_get_count failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get count"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeSetCount(unsigned int count) { + ScopeLogger("id_: %d, count: %u", id_, count); + + int ret = ml_tensors_info_set_count(handle_, count); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_set_count failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to set count"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeGetTensorDimensions(int index, + unsigned int dim[ML_TENSOR_RANK_LIMIT]) { + ScopeLogger("id_: %d, index: %d", id_, index); + + int ret = ml_tensors_info_get_tensor_dimension(handle_, index, dim); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_get_tensor_dimension failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor dimension"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeSetTensorDimensions(int index, + unsigned int dim[ML_TENSOR_RANK_LIMIT]) { + ScopeLogger("id_: %d, index: %d", id_, index); + + int ret = ml_tensors_info_set_tensor_dimension(handle_, index, dim); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_set_tensor_dimension failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to set tensor dimension"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeGetTensorName(int index, std::string* name) { + ScopeLogger("id_: %d, index: %d", id_, index); + + if (nullptr == name) { + LoggerE("name is nullptr"); + return PlatformResult(ErrorCode::ABORT_ERR, "Failed to get tensor name"); + } + + gchar* out_name = nullptr; + int ret = ml_tensors_info_get_tensor_name(handle_, index, &out_name); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_get_tensor_name failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor name"); + } + if (out_name) { + LoggerD("out_name: %s", out_name); + *name = std::string{out_name}; + } else { + *name = std::string{}; + } + + g_free(out_name); + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeSetTensorName(int index, const std::string& name) { + ScopeLogger("id_: %d, index: %d, name: %s", id_, index, name.c_str()); + + int ret = ml_tensors_info_set_tensor_name(handle_, index, name.c_str()); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_set_tensor_name failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to set tensor name"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeGetTensorType(int index, ml_tensor_type_e* type) { + ScopeLogger("id_: %d, index: %d", id_, index); + + int ret = ml_tensors_info_get_tensor_type(handle_, index, type); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_get_tensor_type failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor type"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeSetTensorType(int index, const ml_tensor_type_e type) { + ScopeLogger("id_: %d, index: %d, type: %d", id_, index, type); + + int ret = ml_tensors_info_set_tensor_type(handle_, index, type); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_set_tensor_type failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to set tensor type"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TensorsInfo::NativeGetTensorSize(int index, size_t* size) { + ScopeLogger("id_: %d, index: %d", id_, index); + + int ret = ml_tensors_info_get_tensor_size(handle_, index, size); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_get_tensor_size failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to get tensor size"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +TensorsInfoManager::TensorsInfoManager() : nextId_(0) { + ScopeLogger(); +} + +TensorsInfoManager::~TensorsInfoManager() { + ScopeLogger(); + + map_by_id_.clear(); + map_by_handle_.clear(); +}; + +TensorsInfo* TensorsInfoManager::CreateTensorsInfo() { + ScopeLogger(); + + ml_tensors_info_h handle; + int ret = ml_tensors_info_create(&handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_info_create failed: %d (%s)", ret, get_error_message(ret)); + return nullptr; + } + + 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::GetTensorsInfo(int id) { + ScopeLogger("id: %d", id); + + if (map_by_id_.end() != map_by_id_.find(id)) { + return map_by_id_[id].get(); + } + + return nullptr; +} + +TensorsInfo* TensorsInfoManager::GetTensorsInfo(ml_tensors_info_h handle) { + ScopeLogger(); + + if (map_by_handle_.end() != map_by_handle_.find(handle)) { + return map_by_handle_[handle].get(); + } + return nullptr; +} + +} // ml +} // extension diff --git a/src/ml/ml_tensors_info_manager.h b/src/ml/ml_tensors_info_manager.h new file mode 100644 index 0000000..734a56a --- /dev/null +++ b/src/ml/ml_tensors_info_manager.h @@ -0,0 +1,78 @@ +/* + * 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_INFO_MANAGER_H__ +#define __ML_TENSORS_INFO_MANAGER_H__ + +#include +#include + +#include "common/logger.h" +#include "common/platform_result.h" +#include "ml_utils.h" + +#include + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace ml { + +class TensorsInfo { + public: + TensorsInfo(ml_tensors_info_h handle, int id); + ~TensorsInfo(); + + ml_tensors_info_h Handle(); + int Id(); + + PlatformResult NativeDestroy(); + PlatformResult NativeGetCount(unsigned int* count); + PlatformResult NativeSetCount(unsigned int count); + PlatformResult NativeGetTensorDimensions(int index, unsigned int dim[ML_TENSOR_RANK_LIMIT]); + PlatformResult NativeSetTensorDimensions(int index, unsigned int dim[ML_TENSOR_RANK_LIMIT]); + PlatformResult NativeGetTensorName(int index, std::string* name); + PlatformResult NativeSetTensorName(int index, const std::string& name); + PlatformResult NativeGetTensorType(int index, ml_tensor_type_e* type); + PlatformResult NativeSetTensorType(int index, const ml_tensor_type_e type); + PlatformResult NativeGetTensorSize(int index, size_t* size); + + private: + ml_tensors_info_h handle_; + int id_; +}; + +class TensorsInfoManager { + public: + TensorsInfoManager(); + ~TensorsInfoManager(); + TensorsInfo* CreateTensorsInfo(); + + TensorsInfo* GetTensorsInfo(int id); + TensorsInfo* GetTensorsInfo(ml_tensors_info_h handle); + + private: + TensorsInfoManager(TensorsInfoManager const&) = delete; + TensorsInfoManager& operator=(TensorsInfoManager const&) = delete; + std::map> map_by_id_; + std::map> map_by_handle_; + int nextId_; +}; + +} // ml +} // extension +#endif // __ML_TENSORS_INFO_MANAGER_H__ -- 2.7.4 From 7cc018b2237890b7bad6252b57a0ec9eda1b34a3 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Fri, 8 Jan 2021 16:40:47 +0100 Subject: [PATCH 16/16] [ML][Common] Add TensorsInfo constructor and TensorsInfo::addTensorInfo ACR: TWDAPI-273 Added: - TensorsInfo constructor - TensorsInfo::addTensorInfo method - TensorsInfo::count property Test code: var ti = new tizen.ml.TensorsInfo(); console.log(ti.count) ti.addTensorInfo(null, "UINT8", [1, 1]) console.log(ti.count) console.log(JSON.stringify(ti)) [Verification] Built successful, tested in Chrome Dev console Change-Id: Ic194d71439e4c4ce30b9722de031e9312c1c8183 Signed-off-by: Rafal Walczyna --- src/ml/js/ml_common.js | 76 ++++++++++++++++++- src/ml/ml_instance.cc | 154 ++++++++++++++++++++++++++++++++++---- src/ml/ml_instance.h | 3 + src/ml/ml_tensors_info_manager.cc | 45 ++++++++++- src/ml/ml_tensors_info_manager.h | 5 ++ src/ml/ml_utils.cc | 9 +++ src/ml/ml_utils.h | 1 + 7 files changed, 274 insertions(+), 19 deletions(-) diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 415ff53..77c30eb 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -21,6 +21,9 @@ var native_ = new xwalk.utils.NativeManager(extension); var AbortError = new WebAPIException('AbortError', 'An unknown error occurred'); +// Constants +var MAX_TENSORS_INFO_COUNT = 16; + // TensorRawData var TensorRawData = function() { @@ -93,20 +96,87 @@ TensorsData.prototype.dispose = function() { // TensorsInfo +function tensorsInfoCountGetter(id) { + var result = native_.callSync('MLTensorsInfoCountGetter', { tensorsInfoId: id }); + + if (native_.isFailure(result)) { + return 0; + } else { + return native_.getResultObject(result); + } +} + var TensorsInfo = function() { validator_.isConstructorCall(this, TensorsInfo); + + var result = native_.callSync('MLTensorsInfoCreate'); + if (native_.isFailure(result)) { + throw AbortError; + } + Object.defineProperties(this, { count: { enumerable: true, get: function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + return tensorsInfoCountGetter(this._id); } - } + }, + _id: { value: result.id, writable: false, enumerable: false } }); }; +var TensorsInfoAddTensorInfoValidExceptions = [ + 'InvalidValuesError', + 'TypeMismatchError', + 'NotSupportedError', + 'AbortError' +]; + TensorsInfo.prototype.addTensorInfo = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: types_.STRING, + optional: false, + nullable: true + }, + { + name: 'type', + type: types_.ENUM, + values: Object.values(TensorType), + optional: false + }, + { + name: 'dimensions', + type: types_.ARRAY, + optional: false + } + ]); + + args.dimensions.forEach(function(d) { + if (Number.isInteger(d) == false) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'dimensions array has to contain only integers' + ); + } + }); + + var callArgs = { + name: args.name, + type: args.type, + dimensions: args.dimensions, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoAddTensorInfo', callArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoAddTensorInfoValidExceptions, + AbortError + ); + } }; TensorsInfo.prototype.clone = function() { diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 97d1c37..301333e 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -28,16 +28,44 @@ namespace ml { namespace { const std::string kNnfw = "nnfw"; const std::string kHw = "hw"; -} +const std::string kTensorsInfoId = "tensorsInfoId"; +const std::string kIndex = "index"; +const std::string kType = "type"; +const std::string kName = "name"; +const std::string kDimensions = "dimensions"; +const std::string kId = "id"; +const std::string kDefinition = "definition"; +const std::string kPipelineStateChangeListenerName = "listenerName"; + +} // namespace using namespace common; -#define CHECK_EXIST(args, name, out) \ - if (!args.contains(name)) { \ - LogAndReportError(TypeMismatchException(std::string(name) + " is required argument"), out); \ - return; \ +#define CHECK_EXIST(args, name, out) \ + if (!args.contains(name)) { \ + std::string msg = std::string(name) + " is required argument"; \ + LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, msg), &out); \ + return; \ } +// CHECK_TYPE will throw AbortError by default, but it can be changed by providing +// additional parameter to the macro, i.e.: +// CHECK_TYPE(args, "name", std::string, out, ErrorCode::TYPE_MISMATCH_ERR) +#define CHECK_TYPE(...) CHECK_TYPE_X(__VA_ARGS__, CHECK_TYPE_5, CHECK_TYPE_4)(__VA_ARGS__) +#define CHECK_TYPE_X(_1, _2, _3, _4, _5, EXC_TYPE, ...) EXC_TYPE +#define CHECK_TYPE_5(args, name, type, out, error_type) \ + if (!args.get(name).is()) { \ + std::string msg = std::string(name) + " has invalid type"; \ + LogAndReportError(PlatformResult(error_type, msg), &out); \ + return; \ + } +#define CHECK_TYPE_4(args, name, type, out) \ + CHECK_TYPE_5(args, name, type, out, ErrorCode::ABORT_ERR) + +#define CHECK_ARGS(args, name, type, out) \ + CHECK_EXIST(args, name, out) \ + CHECK_TYPE(args, name, type, out) + MlInstance::MlInstance() : pipeline_manager_{this} { ScopeLogger(); using namespace std::placeholders; @@ -46,7 +74,9 @@ MlInstance::MlInstance() : pipeline_manager_{this} { // Common ML API begin REGISTER_METHOD(MLCheckNNFWAvailability); - + REGISTER_METHOD(MLTensorsInfoCountGetter); + REGISTER_METHOD(MLTensorsInfoAddTensorInfo); + REGISTER_METHOD(MLTensorsInfoCreate); // Common ML API end // Single API begin @@ -87,6 +117,104 @@ void MlInstance::MLCheckNNFWAvailability(const picojson::value& args, picojson:: picojson::value available = picojson::value{availability_val}; ReportSuccess(available, out); } + +void MlInstance::MLTensorsInfoCreate(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + + TensorsInfo* tensorsInfo = GetTensorsInfoManager().CreateTensorsInfo(); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not create new TensorsInfo handle")); + return; + } + out["id"] = picojson::value(static_cast(tensorsInfo->Id())); + ReportSuccess(out); +} + +void MlInstance::MLTensorsInfoCountGetter(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; + } + unsigned int count = 0; + PlatformResult result = tensorsInfo->NativeGetCount(&count); + if (!result) { + ReportError(result, &out); + return; + } + picojson::value val = picojson::value{static_cast(count)}; + ReportSuccess(val, out); +} + +void MlInstance::MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kType, std::string, out); + // kName is nullable + CHECK_EXIST(args, kName, out); + CHECK_ARGS(args, kDimensions, picojson::array, 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; + } + + const std::string& tensorType = args.get(kType).get(); + ml_tensor_type_e tensorTypeEnum = ML_TENSOR_TYPE_UNKNOWN; + PlatformResult result = types::TensorTypeEnum.getValue(tensorType, &tensorTypeEnum); + if (!result) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Error getting value of TensorType"), + &out, + ("TensorTypeEnum.getValue() failed, error: %s", result.message().c_str())); + return; + } + + std::string name; + if (args.get(kName).is()) { + name = args.get(kName).get(); + LoggerD("name: %s", name.c_str()); + } + + unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {1, 1, 1, 1}; + + // CHECK_ARGS has already validated type of kDimensions + auto dim = args.get(kDimensions).get(); + int i = 0; + for (const auto& d : dim) { + if (i >= ML_TENSOR_RANK_LIMIT) { + LoggerD("Provided dimensions array is bigger than supported"); + break; + } + + if (!d.is()) { + LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, + "dimensions array contains an invalid value"), + &out, + ("dimensions array contains an invalid value: %s", d.serialize().c_str())); + return; + } + + dimensions[i] = static_cast(d.get()); + i++; + } + + result = tensorsInfo->AddTensorInfo(name, tensorTypeEnum, dimensions); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} // Common ML API end // Single API begin @@ -95,15 +223,6 @@ void MlInstance::MLCheckNNFWAvailability(const picojson::value& args, picojson:: // Pipeline API begin -namespace { - -const std::string kId = "id"; -const std::string kName = "name"; -const std::string kDefinition = "definition"; -const std::string kPipelineStateChangeListenerName = "listenerName"; - -} // namespace - // PipelineManager::createPipeline() begin namespace { @@ -349,6 +468,11 @@ void MlInstance::MLPipelineGetSwitch(const picojson::value& args, picojson::obje // Pipeline API end #undef CHECK_EXIST +#undef CHECK_TYPE +#undef CHECK_TYPE_X +#undef CHECK_TYPE_4 +#undef CHECK_TYPE_5 +#undef CHECK_ARGS } // namespace ml } // namespace extension diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index ff2f74b..f8141a9 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -37,6 +37,9 @@ class MlInstance : public common::ParsedInstance { private: // Common ML API begin void MLCheckNNFWAvailability(const picojson::value& args, picojson::object& out); + void MLTensorsInfoCountGetter(const picojson::value& args, picojson::object& out); + void MLTensorsInfoCreate(const picojson::value& args, picojson::object& out); + void MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out); TensorsInfoManager tensors_info_manager_; // Common ML API end diff --git a/src/ml/ml_tensors_info_manager.cc b/src/ml/ml_tensors_info_manager.cc index ea80daf..eaf0f1c 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) { +TensorsInfo::TensorsInfo(ml_tensors_info_h handle, int id) : handle_(handle), id_(id), count_(0) { ScopeLogger(); } @@ -41,6 +41,47 @@ int TensorsInfo::Id() { return this->id_; } +int TensorsInfo::Count() { + return this->count_; +} + +PlatformResult TensorsInfo::AddTensorInfo(std::string name, ml_tensor_type_e type, + unsigned int dim[ML_TENSOR_RANK_LIMIT]) { + ScopeLogger("id_: %d", id_); + if (Count() >= ML_TENSOR_SIZE_LIMIT) { + return (PlatformResult(ErrorCode::ABORT_ERR, "Maximum size of tensors info reached.")); + } + int index = Count(); + + PlatformResult result = NativeSetCount(index + 1); + if (!result) { + return result; + } + + if (!name.empty()) { + result = NativeSetTensorName(index, name); + if (!result) { + LoggerD("Failed to set name, reducing tensorsInfo count"); + NativeSetCount(index); + return result; + } + } + + result = NativeSetTensorType(index, type); + if (!result) { + LoggerD("Failed to set type, reducing tensorsInfo count"); + NativeSetCount(index); + return result; + } + + result = NativeSetTensorDimensions(index, dim); + if (!result) { + LoggerD("Failed to set type, reducing tensorsInfo count"); + NativeSetCount(index); + } + return result; +} + PlatformResult TensorsInfo::NativeDestroy() { ScopeLogger("id_: %d", id_); int ret = ml_tensors_info_destroy(handle_); @@ -59,6 +100,7 @@ PlatformResult TensorsInfo::NativeGetCount(unsigned int* count) { LoggerE("ml_tensors_info_get_count failed: %d (%s)", ret, get_error_message(ret)); return util::ToPlatformResult(ret, "Failed to get count"); } + count_ = *count; return PlatformResult(ErrorCode::NO_ERROR); } @@ -70,6 +112,7 @@ PlatformResult TensorsInfo::NativeSetCount(unsigned int count) { LoggerE("ml_tensors_info_set_count failed: %d (%s)", ret, get_error_message(ret)); return util::ToPlatformResult(ret, "Failed to set count"); } + count_ = count; return PlatformResult(ErrorCode::NO_ERROR); } diff --git a/src/ml/ml_tensors_info_manager.h b/src/ml/ml_tensors_info_manager.h index 734a56a..29923b6 100644 --- a/src/ml/ml_tensors_info_manager.h +++ b/src/ml/ml_tensors_info_manager.h @@ -39,6 +39,10 @@ class TensorsInfo { ml_tensors_info_h Handle(); int Id(); + int Count(); + + PlatformResult AddTensorInfo(std::string name, ml_tensor_type_e type, + unsigned int dim[ML_TENSOR_RANK_LIMIT]); PlatformResult NativeDestroy(); PlatformResult NativeGetCount(unsigned int* count); @@ -54,6 +58,7 @@ class TensorsInfo { private: ml_tensors_info_h handle_; int id_; + int count_; }; class TensorsInfoManager { diff --git a/src/ml/ml_utils.cc b/src/ml/ml_utils.cc index d29605d..e021050 100644 --- a/src/ml/ml_utils.cc +++ b/src/ml/ml_utils.cc @@ -46,6 +46,15 @@ const PlatformEnum NNFWTypeEnum{{"ANY", ML_NNFW_TYPE_ANY}, {"TENSORFLOW", ML_NNFW_TYPE_TENSORFLOW}, {"TENSORFLOW_LITE", ML_NNFW_TYPE_TENSORFLOW_LITE}, {"VIVANTE", ML_NNFW_TYPE_VIVANTE}}; + +const PlatformEnum TensorTypeEnum{ + {"INT8", ML_TENSOR_TYPE_INT8}, {"UINT8", ML_TENSOR_TYPE_UINT8}, + {"INT16", ML_TENSOR_TYPE_INT16}, {"UINT16", ML_TENSOR_TYPE_UINT16}, + {"FLOAT32", ML_TENSOR_TYPE_FLOAT32}, {"INT32", ML_TENSOR_TYPE_INT32}, + {"UINT32", ML_TENSOR_TYPE_UINT32}, {"FLOAT64", ML_TENSOR_TYPE_FLOAT64}, + {"INT64", ML_TENSOR_TYPE_INT64}, {"UINT64", ML_TENSOR_TYPE_UINT64}, + {"UNKNOWN", ML_TENSOR_TYPE_UNKNOWN}}; + } // types namespace util { diff --git a/src/ml/ml_utils.h b/src/ml/ml_utils.h index bc476b1..481483e 100644 --- a/src/ml/ml_utils.h +++ b/src/ml/ml_utils.h @@ -34,6 +34,7 @@ namespace types { extern const PlatformEnum HWTypeEnum; extern const PlatformEnum NNFWTypeEnum; +extern const PlatformEnum TensorTypeEnum; } // types -- 2.7.4