diff --git a/bundle.json b/bundle.json index 06ee22904e6c1691f5b05235fe132cab1cd5e78b..f95ed56f43d37ce745d2a0a1642455b324bbe3d5 100644 --- a/bundle.json +++ b/bundle.json @@ -41,9 +41,6 @@ "header_base":"//foundation/ai/neural_network_runtime/interfaces/innerkits/c" } } - ], - "test": [ - "//foundation/ai/neural_network_runtime:nnrt_test_target" ] } } diff --git a/example/drivers/nnrt/BUILD.gn b/example/drivers/nnrt/v1_0/BUILD.gn similarity index 100% rename from example/drivers/nnrt/BUILD.gn rename to example/drivers/nnrt/v1_0/BUILD.gn diff --git a/example/drivers/nnrt/hdi_cpu_service/BUILD.gn b/example/drivers/nnrt/v1_0/hdi_cpu_service/BUILD.gn similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/BUILD.gn rename to example/drivers/nnrt/v1_0/hdi_cpu_service/BUILD.gn diff --git a/example/drivers/nnrt/hdi_cpu_service/include/nnrt_device_service.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/nnrt_device_service.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/nnrt_device_service.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/nnrt_device_service.h diff --git a/example/drivers/nnrt/hdi_cpu_service/include/node_functions.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/node_functions.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/node_functions.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/node_functions.h diff --git a/example/drivers/nnrt/hdi_cpu_service/include/node_registry.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/node_registry.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/node_registry.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/node_registry.h diff --git a/example/drivers/nnrt/hdi_cpu_service/include/prepared_model_service.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/prepared_model_service.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/prepared_model_service.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/prepared_model_service.h diff --git a/example/drivers/nnrt/hdi_cpu_service/include/shared_buffer_parser.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/shared_buffer_parser.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/shared_buffer_parser.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/shared_buffer_parser.h diff --git a/example/drivers/nnrt/hdi_cpu_service/include/validation.h b/example/drivers/nnrt/v1_0/hdi_cpu_service/include/validation.h similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/include/validation.h rename to example/drivers/nnrt/v1_0/hdi_cpu_service/include/validation.h diff --git a/example/drivers/nnrt/hdi_cpu_service/src/nnrt_device_driver.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/nnrt_device_driver.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/nnrt_device_driver.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/nnrt_device_driver.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/nnrt_device_service.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/nnrt_device_service.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/nnrt_device_service.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/nnrt_device_service.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/node_functions.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/node_functions.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/node_functions.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/node_functions.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/node_registry.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/node_registry.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/node_registry.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/node_registry.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/prepared_model_service.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/prepared_model_service.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/prepared_model_service.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/prepared_model_service.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/shared_buffer_parser.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/shared_buffer_parser.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/shared_buffer_parser.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/shared_buffer_parser.cpp diff --git a/example/drivers/nnrt/hdi_cpu_service/src/validation.cpp b/example/drivers/nnrt/v1_0/hdi_cpu_service/src/validation.cpp similarity index 100% rename from example/drivers/nnrt/hdi_cpu_service/src/validation.cpp rename to example/drivers/nnrt/v1_0/hdi_cpu_service/src/validation.cpp diff --git a/example/drivers/nnrt/v2_0/BUILD.gn b/example/drivers/nnrt/v2_0/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..28ca28bae4175fdbc5f5efc5da300d89c224fc8a --- /dev/null +++ b/example/drivers/nnrt/v2_0/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# 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. + +if (defined(ohos_lite)) { + group("nnrt_entry") { + deps = [ ] + } +} else { + group("nnrt_entry") { + deps = [ + "./hdi_cpu_service:hdf_nnrt_service", + ] + } +} \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/BUILD.gn b/example/drivers/nnrt/v2_0/hdi_cpu_service/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..003de74006247cbf4e9e469cb04a074045661b6d --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/BUILD.gn @@ -0,0 +1,90 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") +import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + +ohos_prebuilt_shared_library("mindspore_demo") { + source = "//drivers/peripheral/nnrt/v2_0/mindspore/mindspore/libmindspore-lite.huawei.so" + + install_images = [chipset_base_dir] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nnrt" +} + +ohos_shared_library("libnnrt_device_service_2.0") { + include_dirs = [ + "//drivers/peripheral/nnrt/v2_0/hdi_cpu_service/include", + "//drivers/peripheral/nnrt/v2_0/mindspore", + "//third_party/flatbuffers/include", + "//commonlibrary/c_utils/base/include" + ] + sources = [ + "src/nnrt_device_service.cpp", + "src/prepared_model_service.cpp", + "src/node_registry.cpp", + "src/node_functions.cpp", + "src/shared_buffer_parser.cpp", + "src/validation.cpp" + ] + + deps = [ + "//drivers/interface/nnrt/v2_0:nnrt_idl_headers", + "//drivers/interface/nnrt/v2_0:libnnrt_stub_2.0", + ":mindspore_demo" + ] + + external_deps = [ + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "c_utils:utils" + ] + + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nnrt" +} + +ohos_shared_library("libnnrt_driver") { + include_dirs = [] + sources = [ + "src/nnrt_device_driver.cpp" + ] + deps = [ + "//drivers/peripheral/nnrt/v2_0/hdi_cpu_service:libnnrt_device_service_2.0", + "//drivers/interface/nnrt/v2_0:libnnrt_stub_2.0" + ] + + external_deps = [ + "hdf_core:libhdf_host", + "hdf_core:libhdf_ipc_adapter", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "c_utils:utils", + "hdf_core:libhdi" + ] + + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nnrt" +} + +group("hdf_nnrt_service") { + deps = [ + ":mindspore_demo", + ":libnnrt_driver", + ":libnnrt_device_service_2.0", + ] +} \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/nnrt_device_service.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/nnrt_device_service.h new file mode 100644 index 0000000000000000000000000000000000000000..9419f4082fdf5f3793732204a5236fcd47b3a81e --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/nnrt_device_service.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNRT_V2_0_NNRTDEVICESERVICE_H +#define OHOS_HDI_NNRT_V2_0_NNRTDEVICESERVICE_H + +#include + +#include "v2_0/innrt_device.h" +#include "ashmem.h" +#include "include/api/model.h" + +#include "mindspore_schema/model_generated.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +class NnrtDeviceService : public INnrtDevice { +public: + NnrtDeviceService() = default; + virtual ~NnrtDeviceService(); + + int32_t GetDeviceName(std::string& name) override; + + int32_t GetVendorName(std::string& name) override; + + int32_t GetDeviceType(DeviceType& deviceType) override; + + int32_t GetDeviceStatus(DeviceStatus& status) override; + + int32_t GetSupportedOperation(const Model& model, std::vector& ops) override; + + int32_t IsFloat16PrecisionSupported(bool& isSupported) override; + + int32_t IsPerformanceModeSupported(bool& isSupported) override; + + int32_t IsPrioritySupported(bool& isSupported) override; + + int32_t IsDynamicInputSupported(bool& isSupported) override; + + int32_t PrepareModel(const Model& model, const ModelConfig& config, sptr& preparedModel) override; + + int32_t IsModelCacheSupported(bool& isSupported) override; + + int32_t PrepareModelFromModelCache(const std::vector& modelCache, const ModelConfig& config, + sptr& preparedModel) override; + + int32_t AllocateBuffer(uint32_t length, SharedBuffer& buffer) override; + + int32_t ReleaseBuffer(const SharedBuffer& buffer) override; + +private: + int32_t ValidateModelConfig(const ModelConfig& config) const; + int32_t ValidateModel(const Model& model) const; + std::shared_ptr TransModelToGraph(const Model& model) const; + std::unique_ptr TransTensor(const Tensor& tensor) const; + std::unique_ptr TransNode(const Node& node) const; + std::unique_ptr TransSubGraph(const SubGraph& graph, const size_t numTensor) const; + std::shared_ptr TransModelConfig(const ModelConfig& config) const; + int32_t ShowCustomAttributes(const std::map>& extensions) const; + int32_t ParseCustomAttributes(const std::map>& extensions, float& attr1, + std::string& attr2) const; + int32_t ConvertVecToFloat(std::vector vecFloat, float& result) const; + int32_t ConvertVecToString(std::vector vecFloat, std::string& result) const; + +private: + std::shared_ptr m_model {nullptr}; + std::unordered_map> m_ashmems; +}; +} // V2_0 +} // Nnrt +} // HDI +} // OHOS + +#endif // OHOS_HDI_NNRT_V2_0_NNRTDEVICESERVICE_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_functions.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..8e1fbb3af4cafd447d8550393579fe6d96d75f2a --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_functions.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNR_NODE_FUNCTIONS_H +#define OHOS_HDI_NNR_NODE_FUNCTIONS_H + +#include + +#include "hdf_base.h" +#include "hdf_log.h" +#include +#include "node_registry.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +template +int32_t ParsePrimitive(const std::vector& primitive, T& attr, + std::function parseFunc) +{ + if (primitive.empty()) { + HDF_LOGE("Primitive data is empty."); + return HDF_FAILURE; + } + + OHOS::MessageParcel parcelData; + bool ret = parcelData.WriteBuffer(primitive.data(), primitive.size()); + if (!ret) { + HDF_LOGE("Write data to MessageParcel failed."); + return HDF_FAILURE; + } + + ret = parseFunc(parcelData, attr); + if (!ret) { + HDF_LOGE("Unmarshalling data failed."); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +PrimUniquePtr GetAddPrimitive(const std::vector& primitive); +PrimUniquePtr GetAvgPoolPrimitive(const std::vector& primitive); +PrimUniquePtr GetConcatPrimitive(const std::vector& primitive); +PrimUniquePtr GetConv2dPrimitive(const std::vector& primitive); +PrimUniquePtr GetFullConnectionPrimitive(const std::vector& primitive); +PrimUniquePtr GetMaxPoolFusionPrimitive(const std::vector& primitive); +PrimUniquePtr GetMatMulFusionPrimitive(const std::vector& primitive); +PrimUniquePtr GetSoftmaxPrimitive(const std::vector& primitive); +PrimUniquePtr GetReshapePrimitive(const std::vector& primitive); +PrimUniquePtr GetScaleFusionPrimitive(const std::vector& primitive); +PrimUniquePtr GetActivationPrimitive(const std::vector& primitive); +PrimUniquePtr GetQuantDTypeCastPrimitive(const std::vector& primitive); +PrimUniquePtr GetMulFusionPrimitive(const std::vector& primitive); +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS +#endif // OHOS_HDI_NNR_NODE_FUNCTIONS_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_registry.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_registry.h new file mode 100644 index 0000000000000000000000000000000000000000..17d4b510082ccdb41c13a98605940939d00b6cf3 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/node_registry.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNR_NODE_REGISTRY_H +#define OHOS_HDI_NNR_NODE_REGISTRY_H + +#include +#include +#include + +#include "v2_0/nnrt_types.h" +#include "mindspore_schema/model_generated.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +using PrimUniquePtr = std::unique_ptr; +class NodeRegistry { +public: + struct Registrar { + Registrar() = delete; + Registrar(NodeType type, std::function&)> nodeFunc); + }; + +public: + static NodeRegistry& GetSingleton(); + std::function&)> GetNodeFunc(NodeType type) const; + bool IsNodeTypeExist(NodeType type) const; + +private: + NodeRegistry() {}; + NodeRegistry(const NodeRegistry&) = delete; + NodeRegistry& operator=(const NodeRegistry&) = delete; + +private: + std::unordered_map&)>> m_nodeRegs; +}; + +#define REGISTER_NODE(nodeName, nodeType, funcPtr) static NodeRegistry::Registrar g_##nodeName(nodeType, funcPtr) +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS +#endif // OHOS_HDI_NNR_NODE_REGISTRY_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/prepared_model_service.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/prepared_model_service.h new file mode 100644 index 0000000000000000000000000000000000000000..c52ed06b1aa09b022bd58eabd4bcdf97b5011353 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/prepared_model_service.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNR_V2_0_PREPAREDMODELSERVICE_H +#define OHOS_HDI_NNR_V2_0_PREPAREDMODELSERVICE_H + +#include "v2_0/iprepared_model.h" +#include "include/api/data_type.h" +#include "include/api/context.h" +#include "include/api/types.h" +#include "include/api/model.h" +#include "mindspore_schema/model_generated.h" +#include "ashmem.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +constexpr int DYNAMIC_SHAPE_FLAG = -1; +class PreparedModelService : public IPreparedModel { +public: + PreparedModelService() = default; + + virtual ~PreparedModelService(); + + explicit PreparedModelService(std::shared_ptr context); + + int32_t Compile(std::shared_ptr graph); + + int32_t Compile(const void* modelBuffer, size_t length); + + int32_t ExportModelCache(std::vector& modelCache) override; + + int32_t Run(const std::vector& inputs, const std::vector& outputs, + std::vector>& outputsDims, std::vector& isOutputBufferEnough) override; + + int32_t GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims) override; + +private: + int32_t SetInputs(const std::vector& inputs); + int32_t SetOutputs(const std::vector& outputs); + int32_t GetMSInputsAndOutputs(); + int32_t CompareTensor(const IOTensor& tensor, const mindspore::MSTensor& msTensor); + sptr ParseBuffer(const SharedBuffer& buffer); + int32_t UpdateOutput(const std::vector& outputs, + std::vector>& outputsDims, std::vector& isOutputBufferEnough); + void ResetInputAndOutput(); + +private: + std::shared_ptr m_graph {nullptr}; + std::shared_ptr m_context {nullptr}; + flatbuffers::FlatBufferBuilder m_builder; + std::shared_ptr m_model {nullptr}; + sptr m_cacheBuffer {nullptr}; + std::vector> m_inputAshmems; + std::vector m_inputs; + std::vector> m_outputAshmems; + std::vector m_outputs; + std::vector> m_inputDims; + bool m_isDynamicShape {false}; +}; +} // V2_0 +} // Nnrt +} // HDI +} // OHOS + +#endif // OHOS_HDI_NNR_V2_0_PREPAREDMODELSERVICE_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/shared_buffer_parser.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/shared_buffer_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..8e74154168b9ed727200c8f5812504ebffce65d6 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/shared_buffer_parser.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNR_V2_0_SHARED_BUFFER_PARSER_H +#define OHOS_HDI_NNR_V2_0_SHARED_BUFFER_PARSER_H + +#include "ashmem.h" +#include "v2_0/nnrt_types.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +namespace { +const int INVALID_FD = -1; +} + +class SharedBufferParser { +public: + SharedBufferParser() {}; + ~SharedBufferParser(); + + int32_t Init(const SharedBuffer& buffer); + int32_t Init(const std::string& name, int32_t size); + void* GetBufferPtr(); + SharedBuffer GetBuffer(); + +private: + SharedBuffer m_buffer; + sptr m_ashptr {nullptr}; + void* m_bufferAddr {nullptr}; +}; +} // V2_0 +} // Nnrt +} // HDI +} // OHOS +#endif // OHOS_HDI_NNR_V2_0_SHARED_BUFFER_PARSER_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/include/validation.h b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/validation.h new file mode 100644 index 0000000000000000000000000000000000000000..ffcdf50687ee4c91a4bc721cdf081681ecf116a0 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/include/validation.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNRT_VALIDATION_H +#define OHOS_HDI_NNRT_VALIDATION_H + +#include "v2_0/nnrt_types.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +int32_t ValidatePerformanceMode(PerformanceMode mode); +int32_t ValidatePriority(Priority priority); +int32_t ValidateDataType(DataType dataType); +int32_t ValidateFormat(Format format); +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS +#endif // OHOS_HDI_NNRT_VALIDATION_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_driver.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_driver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fab6e89d9c5b7e7edb5d1f95780a97a57f3a430c --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_driver.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 +#include +#include +#include "v2_0/nnrt_device_stub.h" + +using namespace OHOS::HDI::Nnrt::V2_0; + +struct HdfNnrtDeviceHost { + struct IDeviceIoService ioService; + OHOS::sptr stub; +}; + +static int32_t NnrtDeviceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, + struct HdfSBuf *reply) +{ + auto *hdfNnrtDeviceHost = CONTAINER_OF(client->device->service, struct HdfNnrtDeviceHost, ioService); + + OHOS::MessageParcel *dataParcel = nullptr; + OHOS::MessageParcel *replyParcel = nullptr; + OHOS::MessageOption option; + + if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + + return hdfNnrtDeviceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); +} + +static int HdfNnrtDeviceDriverInit(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("HdfNnrtDeviceDriverInit enter"); + return HDF_SUCCESS; +} + +static int HdfNnrtDeviceDriverBind(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("HdfNnrtDeviceDriverBind enter"); + + auto *hdfNnrtDeviceHost = new (std::nothrow) HdfNnrtDeviceHost; + if (hdfNnrtDeviceHost == nullptr) { + HDF_LOGE("%{public}s: failed to create create HdfNnrtDeviceHost object", __func__); + return HDF_FAILURE; + } + + hdfNnrtDeviceHost->ioService.Dispatch = NnrtDeviceDriverDispatch; + hdfNnrtDeviceHost->ioService.Open = NULL; + hdfNnrtDeviceHost->ioService.Release = NULL; + + auto serviceImpl = INnrtDevice::Get(true); + if (serviceImpl == nullptr) { + HDF_LOGE("%{public}s: failed to get of implement service", __func__); + delete hdfNnrtDeviceHost; + return HDF_FAILURE; + } + + hdfNnrtDeviceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, + INnrtDevice::GetDescriptor()); + if (hdfNnrtDeviceHost->stub == nullptr) { + HDF_LOGE("%{public}s: failed to get stub object", __func__); + delete hdfNnrtDeviceHost; + return HDF_FAILURE; + } + + deviceObject->service = &hdfNnrtDeviceHost->ioService; + return HDF_SUCCESS; +} + +static void HdfNnrtDeviceDriverRelease(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("HdfNnrtDeviceDriverRelease enter"); + if (deviceObject->service == nullptr) { + HDF_LOGE("HdfNnrtDeviceDriverRelease not initted"); + return; + } + + auto *hdfNnrtDeviceHost = CONTAINER_OF(deviceObject->service, struct HdfNnrtDeviceHost, ioService); + delete hdfNnrtDeviceHost; +} + +struct HdfDriverEntry g_nnrtdeviceDriverEntry = { + .moduleVersion = 2, + .moduleName = "nnrt", + .Bind = HdfNnrtDeviceDriverBind, + .Init = HdfNnrtDeviceDriverInit, + .Release = HdfNnrtDeviceDriverRelease, +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +HDF_INIT(g_nnrtdeviceDriverEntry); +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_service.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77ca2390167d0cabb31a09bf1a511c220a5debd5 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/nnrt_device_service.cpp @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "nnrt_device_service.h" + +#include +#include "hdf_log.h" +#include "ashmem.h" +#include "securec.h" + +#include "node_registry.h" +#include "prepared_model_service.h" +#include "shared_buffer_parser.h" +#include "validation.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +extern "C" INnrtDevice *NnrtDeviceImplGetInstance(void) +{ + return new (std::nothrow) NnrtDeviceService(); +} + +NnrtDeviceService::~NnrtDeviceService() +{ + for (auto ash : m_ashmems) { + ash.second->UnmapAshmem(); + ash.second->CloseAshmem(); + } +} + +int32_t NnrtDeviceService::GetDeviceName(std::string& name) +{ + name = "RK3568-CPU"; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::GetVendorName(std::string& name) +{ + name = "Rockchip"; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::GetDeviceType(DeviceType& deviceType) +{ + deviceType = DeviceType::CPU; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::GetDeviceStatus(DeviceStatus& status) +{ + status = DeviceStatus::AVAILABLE; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::GetSupportedOperation(const Model& model, std::vector& ops) +{ + size_t nodeSize = model.nodes.size(); + auto nodes = model.nodes; + ops.resize(nodeSize, false); + auto& regInstance = NodeRegistry::GetSingleton(); + for (size_t i = 0; i < nodeSize; i++) { + ops[i] = regInstance.IsNodeTypeExist(nodes[i].nodeType); + } + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::IsFloat16PrecisionSupported(bool& isSupported) +{ + isSupported = true; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::IsPerformanceModeSupported(bool& isSupported) +{ + isSupported = true; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::IsPrioritySupported(bool& isSupported) +{ + isSupported = false; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::IsDynamicInputSupported(bool& isSupported) +{ + isSupported = true; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ShowCustomAttributes(const std::map>& extensions) const +{ + float attr1{0.0}; + std::string attr2; + + auto ret = ParseCustomAttributes(extensions, attr1, attr2); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parsing custom attributes failed."); + return ret; + } + + if (attr1 != 0.0f) { + HDF_LOGI("Set attr1: %f", attr1); + } + + if (!attr2.empty()) { + HDF_LOGI("Set attr2: %s", attr2.c_str()); + } + + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::PrepareModel(const Model& model, const ModelConfig& config, + sptr& preparedModel) +{ + auto ret = ValidateModel(model); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Model is invalid."); + return ret; + } + + auto graph = TransModelToGraph(model); + if (graph == nullptr) { + HDF_LOGE("Transfrom model to graph failed."); + return HDF_ERR_INVALID_PARAM; + } + + ret = ValidateModelConfig(config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("ModelConfig is invalid."); + return ret; + } + + ret = ShowCustomAttributes(config.extensions); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Showing custom attributes failed."); + return ret; + } + + auto context = TransModelConfig(config); + sptr service = new (std::nothrow) PreparedModelService(context); + if (service == nullptr) { + HDF_LOGE("Create new PreparedModelService instance failed."); + return HDF_ERR_MALLOC_FAIL; + } + + ret = service->Compile(graph); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Prepared model failed."); + return ret; + } + + preparedModel = service; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::IsModelCacheSupported(bool& isSupported) +{ + isSupported = true; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::PrepareModelFromModelCache(const std::vector& modelCache, + const ModelConfig& config, sptr& preparedModel) +{ + HDF_LOGD("Using cache to prepare model."); + + // modelCache must be 1, because PreparedModel only export one cache file. + if (modelCache.size() != 1) { + HDF_LOGE("The size of modelCache vector is not valid, it should be one elememt in that vector."); + return HDF_ERR_INVALID_PARAM; + } + + SharedBufferParser parser; + auto ret = parser.Init(modelCache[0]); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse modle buffer failed."); + return HDF_ERR_INVALID_PARAM; + } + + ret = ValidateModelConfig(config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("ModelConfig is invalid."); + return ret; + } + + ret = ShowCustomAttributes(config.extensions); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Showing custom attributes failed."); + return ret; + } + + auto context = TransModelConfig(config); + sptr service = new (std::nothrow) PreparedModelService(context); + if (service == nullptr) { + HDF_LOGE("Create new instance PreparedModelService failed."); + return HDF_ERR_MALLOC_FAIL; + } + + void* modelBuffer = parser.GetBufferPtr(); + ret = service->Compile(modelBuffer, modelCache[0].dataSize); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Prepared model failed."); + return ret; + } + + preparedModel = service; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::AllocateBuffer(uint32_t length, SharedBuffer& buffer) +{ + sptr ashptr = Ashmem::CreateAshmem("allocateBuffer", length); + if (ashptr == nullptr) { + HDF_LOGE("Create shared memory failed."); + return HDF_FAILURE; + } + + if (!ashptr->MapReadAndWriteAshmem()) { + HDF_LOGE("Map allocate buffer failed."); + return HDF_FAILURE; + } + + buffer.fd = ashptr->GetAshmemFd(); + buffer.bufferSize = ashptr->GetAshmemSize(); + buffer.offset = 0; + buffer.dataSize = length; + + m_ashmems[buffer.fd] = ashptr; + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ReleaseBuffer(const SharedBuffer& buffer) +{ + // parser will close current fd. + SharedBufferParser parser; + auto ret = parser.Init(buffer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse buffer failed."); + return HDF_ERR_INVALID_PARAM; + } + + for (auto& ash : m_ashmems) { + ash.second->UnmapAshmem(); + ash.second->CloseAshmem(); + } + m_ashmems.clear(); + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ValidateModelConfig(const ModelConfig& config) const +{ + if (!ValidatePerformanceMode(config.mode)) { + HDF_LOGE("PerformanceMode is invalid. mode=%d", config.mode); + return HDF_ERR_INVALID_PARAM; + } + + if (!ValidatePriority(config.priority)) { + HDF_LOGE("Priority is invalid. priority=%d", config.priority); + return HDF_ERR_INVALID_PARAM; + } + + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ValidateModel(const Model& model) const +{ + if (model.allTensors.empty()) { + HDF_LOGE("Model has no tensors."); + return HDF_ERR_INVALID_PARAM; + } + + if (model.subGraph.empty()) { + HDF_LOGE("Model has no subGraphs."); + return HDF_ERR_INVALID_PARAM; + } + + if (model.nodes.empty()) { + HDF_LOGE("Model has no nodes."); + return HDF_ERR_INVALID_PARAM; + } + + if (model.inputIndex.empty()) { + HDF_LOGE("Model has no input."); + return HDF_ERR_INVALID_PARAM; + } + + if (model.outputIndex.empty()) { + HDF_LOGE("Model has no output."); + return HDF_ERR_INVALID_PARAM; + } + + size_t tensorSize = model.allTensors.size(); + for (auto index : model.inputIndex) { + if (index > tensorSize) { + HDF_LOGE("Input index is invalid, index=%u", index); + return HDF_ERR_INVALID_PARAM; + } + } + + for (auto index : model.outputIndex) { + if (index > tensorSize) { + HDF_LOGE("Output index is invalid, index=%u", index); + return HDF_ERR_INVALID_PARAM; + } + } + + return HDF_SUCCESS; +} + +std::shared_ptr NnrtDeviceService::TransModelToGraph(const Model& model) const +{ + auto metaGraph = std::make_shared(); + metaGraph->name = model.name; + metaGraph->version = mindspore::Version(); + + std::unique_ptr transTensor{nullptr}; + for (auto tensor : model.allTensors) { + transTensor = TransTensor(tensor); + if (transTensor == nullptr) { + HDF_LOGE("Transform tensor failed."); + return nullptr; + } + metaGraph->allTensors.emplace_back(std::move(transTensor)); + } + metaGraph->inputIndex = model.inputIndex; + metaGraph->outputIndex = model.outputIndex; + + // Transform node + std::unique_ptr transNode {nullptr}; + for (auto& node : model.nodes) { + transNode = TransNode(node); + if (transNode == nullptr) { + HDF_LOGE("Transform node failed, node name=%{public}s", node.name.c_str()); + return nullptr; + } + metaGraph->nodes.emplace_back(std::move(transNode)); + } + + // Transform subgraph + const size_t numTensor = model.allTensors.size(); + for (auto graph : model.subGraph) { + metaGraph->subGraph.emplace_back(TransSubGraph(graph, numTensor)); + } + return metaGraph; +} + +std::unique_ptr NnrtDeviceService::TransTensor(const Tensor& tensor) const +{ + if (!ValidateDataType(tensor.dataType)) { + HDF_LOGE("DataType of tensor is invalid. dataType=%d", tensor.dataType); + return nullptr; + } + + if (!ValidateFormat(tensor.format)) { + HDF_LOGE("Format of tensor is invalid. format=%d", tensor.format); + return nullptr; + } + + auto schemaTensor = std::make_unique(); + schemaTensor->name = tensor.name; + schemaTensor->dataType = static_cast(tensor.dataType); + schemaTensor->format = static_cast(tensor.format); + schemaTensor->dims = tensor.dims; + for (auto param : tensor.quantParams) { + auto quantParam = std::make_unique(); + quantParam->scale = param.scale; + quantParam->zeroPoint = param.zeroPoint; + quantParam->numBits = param.numBits; + quantParam->inited = true; + schemaTensor->quantParams.emplace_back(std::move(quantParam)); + } + + if (tensor.data.fd != INVALID_FD) { + SharedBufferParser parser; + auto ret = parser.Init(tensor.data); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse tensor data failed."); + return nullptr; + } + + auto data = parser.GetBufferPtr(); + schemaTensor->data.resize(tensor.data.dataSize); + auto memRet = memcpy_s(const_cast(schemaTensor->data.data()), + tensor.data.dataSize, data, tensor.data.dataSize); + if (memRet != EOK) { + HDF_LOGW("Copy tensor data failed."); + return nullptr; + } + } + return schemaTensor; +} + +std::unique_ptr NnrtDeviceService::TransNode(const Node& node) const +{ + auto cnode = std::make_unique(); + cnode->name = node.name; + cnode->inputIndex = node.inputIndex; + cnode->outputIndex = node.outputIndex; + cnode->quantType = static_cast(node.quantType); + + auto& regInstance = NodeRegistry::GetSingleton(); + auto parseFunc = regInstance.GetNodeFunc(node.nodeType); + auto primitive = parseFunc(node.nodeAttr); + if (primitive == nullptr) { + HDF_LOGE("Parse primitve data failed. node name=%{public}s", node.name.c_str()); + return nullptr; + } + + cnode->primitive = std::move(primitive); + return cnode; +} + +std::unique_ptr NnrtDeviceService::TransSubGraph(const SubGraph& graph, + const size_t numTensor) const +{ + auto subGraph = std::make_unique(); + subGraph->name = graph.name; + subGraph->inputIndices = graph.inputIndices; + subGraph->outputIndices = graph.outputIndices; + subGraph->nodeIndices = graph.nodeIndices; + subGraph->tensorIndices.reserve(numTensor); + for (size_t i = 0; i < numTensor; i++) { + subGraph->tensorIndices.emplace_back(static_cast(i)); + } + return subGraph; +} + +std::shared_ptr NnrtDeviceService::TransModelConfig(const ModelConfig& config) const +{ + auto context = std::make_shared(); + const int cpuThreadNum = 2; + const int cpuNoAffinities = 0; + const int cpuBigCore = 1; + const int cpuLittleCore = 2; + context->SetThreadNum(cpuThreadNum); + + int mode = cpuNoAffinities; + switch (config.mode) { + case PerformanceMode::PERFORMANCE_LOW: + case PerformanceMode::PERFORMANCE_MEDIUM: + mode = cpuLittleCore; + break; + case PerformanceMode::PERFORMANCE_HIGH: + case PerformanceMode::PERFORMANCE_EXTREME: + mode = cpuBigCore; + break; + default: + mode = cpuNoAffinities; + } + context->SetThreadAffinity(mode); + + auto cpuInfo = std::make_shared(); + cpuInfo->SetEnableFP16(config.enableFloat16); + auto& deviceInfos = context->MutableDeviceInfo(); + deviceInfos.emplace_back(cpuInfo); + return context; +} + +int32_t NnrtDeviceService::ConvertVecToFloat(std::vector vecFloat, float& result) const +{ + if (vecFloat.size() != sizeof(float)) { + HDF_LOGE("Size of the int8_t vector dose not match a float value."); + return HDF_ERR_INVALID_PARAM; + } + + result = *(reinterpret_cast(vecFloat.data())); + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ConvertVecToString(std::vector vecFloat, std::string& result) const +{ + if (vecFloat.empty()) { + HDF_LOGE("int8_t vector is empty."); + return HDF_ERR_INVALID_PARAM; + } + + result = reinterpret_cast(vecFloat.data()); + return HDF_SUCCESS; +} + +int32_t NnrtDeviceService::ParseCustomAttributes(const std::map>& extensions, + float& attr1, std::string& attr2) const +{ + int32_t ret; + for (auto extension : extensions) { + if (extension.first == "attr1") { + ret = ConvertVecToFloat(extension.second, attr1); + if (ret != HDF_SUCCESS) { + HDF_LOGE("ConvertVecToFloat failed."); + return ret; + } + if (attr1 <= 0.0f || attr1 > 1.0f) { + HDF_LOGE("attr1 is out of range (0,1]."); + return HDF_ERR_INVALID_PARAM; + } + } else if (extension.first == "attr2") { + ret = ConvertVecToString(extension.second, attr2); + if (ret != HDF_SUCCESS) { + HDF_LOGE("ConvertVecToString failed."); + return ret; + } + if (attr2 != "LOW" || attr2 != "HIGH") { + HDF_LOGE("attr2 is neither LOW nor HIGH."); + return HDF_ERR_INVALID_PARAM; + } + } + } + + return HDF_SUCCESS; +} +} // V2_0 +} // Nnrt +} // HDI +} // OHOS diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_functions.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_functions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb7a701500fab6bfdb39486155f14e49eb69ac3a --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_functions.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "node_functions.h" + +#include "node_registry.h" +#include +#include + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +PrimUniquePtr GetAddPrimitive(const std::vector& primitive) +{ + AddFusion addAttr; + auto ret = ParsePrimitive(primitive, addAttr, AddFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of AddFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_AddFusion; + auto attr = new (std::nothrow) mindspore::schema::AddFusionT; + if (attr == nullptr) { + HDF_LOGE("Create AddFusion primitive failed."); + return nullptr; + } + attr->activation_type = static_cast(addAttr.activationType); + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetAvgPoolPrimitive(const std::vector& primitive) +{ + AvgPoolFusion avgPoolAttr; + auto ret = ParsePrimitive(primitive, avgPoolAttr, AvgPoolFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of AvgPoolFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_AvgPoolFusion; + + auto attr = new (std::nothrow) mindspore::schema::AvgPoolFusionT; + if (attr == nullptr) { + HDF_LOGE("Create AvgPoolFusion primitive failed."); + return nullptr; + } + attr->kernel_size = avgPoolAttr.kernelSize; + attr->strides = avgPoolAttr.strides; + attr->pad = avgPoolAttr.pad; + attr->pad_mode = static_cast(avgPoolAttr.padMode); + attr->round_mode = static_cast(avgPoolAttr.roundMode); + attr->format = static_cast(avgPoolAttr.format); + attr->global = avgPoolAttr.global; + attr->activation_type = static_cast(avgPoolAttr.activationType); + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetConcatPrimitive(const std::vector& primitive) +{ + Concat concatAttr; + auto ret = ParsePrimitive(primitive, concatAttr, ConcatBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of Concat operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_Concat; + + auto attr = new (std::nothrow) mindspore::schema::ConcatT; + if (attr == nullptr) { + HDF_LOGE("Create concat primitive failed."); + return nullptr; + } + attr->axis = concatAttr.axis; + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetConv2dPrimitive(const std::vector& primitive) +{ + Conv2DFusion conv2dAttr; + auto ret = ParsePrimitive(primitive, conv2dAttr, Conv2DFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of Conv2DFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_Conv2DFusion; + + auto attr = new (std::nothrow) mindspore::schema::Conv2DFusionT; + if (attr == nullptr) { + HDF_LOGE("Create Conv2DFusion primitive failed."); + return nullptr; + } + + attr->kernel_size = conv2dAttr.kernelSize; + attr->stride = conv2dAttr.stride; + attr->dilation = conv2dAttr.dilation; + attr->pad_mode = static_cast(conv2dAttr.padMode); + attr->pad_list = conv2dAttr.padList; + attr->group = conv2dAttr.group; + attr->in_channel = conv2dAttr.inChannel; + attr->out_channel = conv2dAttr.outChannel; + attr->activation_type = static_cast(conv2dAttr.activationType); + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetFullConnectionPrimitive(const std::vector& primitive) +{ + FullConnection fullConnAttr; + auto ret = ParsePrimitive(primitive, fullConnAttr, FullConnectionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of FullConnection operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_FullConnection; + + auto attr = new (std::nothrow) mindspore::schema::FullConnectionT; + if (attr == nullptr) { + HDF_LOGE("Create FullConnection primitive failed."); + return nullptr; + } + + attr->has_bias = fullConnAttr.hasBias; + attr->use_axis = fullConnAttr.useAxis; + attr->axis = fullConnAttr.axis; + attr->activation_type = static_cast(fullConnAttr.activationType); + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetMaxPoolFusionPrimitive(const std::vector& primitive) +{ + MaxPoolFusion maxPoolAttr; + auto ret = ParsePrimitive(primitive, maxPoolAttr, MaxPoolFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of MaxPoolFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_MaxPoolFusion; + + auto attr = new (std::nothrow) mindspore::schema::MaxPoolFusionT; + if (attr == nullptr) { + HDF_LOGE("Create MaxPoolFusion primitive failed."); + return nullptr; + } + + attr->kernel_size = maxPoolAttr.kernelSize; + attr->strides = maxPoolAttr.strides; + attr->pad = maxPoolAttr.pad; + attr->pad_mode = static_cast(maxPoolAttr.padMode); + attr->format = static_cast(maxPoolAttr.format); + attr->global = maxPoolAttr.global; + attr->activation_type = static_cast(maxPoolAttr.activationType); + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetMatMulFusionPrimitive(const std::vector& primitive) +{ + MatMulFusion matmulAttr; + auto ret = ParsePrimitive(primitive, matmulAttr, MatMulFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of MatMulFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_MatMulFusion; + + auto attr = new (std::nothrow) mindspore::schema::MatMulFusionT; + if (attr == nullptr) { + HDF_LOGE("Create MatMulFusion primitive failed."); + return nullptr; + } + + attr->transpose_a = matmulAttr.transposeA; + attr->transpose_b = matmulAttr.transposeB; + attr->activation_type = static_cast(matmulAttr.activationType); + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetSoftmaxPrimitive(const std::vector& primitive) +{ + Softmax softmaxAttr; + auto ret = ParsePrimitive(primitive, softmaxAttr, SoftmaxBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of Softmax operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_Softmax; + + auto attr = new (std::nothrow) mindspore::schema::SoftmaxT; + if (attr == nullptr) { + HDF_LOGE("Create Softmax primitive failed."); + return nullptr; + } + + attr->axis = softmaxAttr.axis; + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetReshapePrimitive(const std::vector& primitive) +{ + Reshape reshapeAttr; + auto ret = ParsePrimitive(primitive, reshapeAttr, ReshapeBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of Reshape operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_Reshape; + + auto attr = new (std::nothrow) mindspore::schema::ReshapeT; + if (attr == nullptr) { + HDF_LOGE("Create Reshape primitive failed."); + return nullptr; + } + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetScaleFusionPrimitive(const std::vector& primitive) +{ + ScaleFusion scaleAttr; + auto ret = ParsePrimitive(primitive, scaleAttr, ScaleFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of ScaleFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_ScaleFusion; + + auto attr = new (std::nothrow) mindspore::schema::ScaleFusionT; + if (attr == nullptr) { + HDF_LOGE("Create ScaleFusion primitive failed."); + return nullptr; + } + + attr->axis = scaleAttr.axis; + attr->activation_type = static_cast(scaleAttr.activationType); + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetActivationPrimitive(const std::vector& primitive) +{ + Activation actAttr; + auto ret = ParsePrimitive(primitive, actAttr, ActivationBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of Activation operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_Activation; + + auto attr = new (std::nothrow) mindspore::schema::ActivationT; + if (attr == nullptr) { + HDF_LOGE("Create Activation primitive failed."); + return nullptr; + } + + attr->alpha = actAttr.alpha; + attr->min_val = actAttr.minVal; + attr->max_val = actAttr.maxVal; + attr->approximate = actAttr.approximate; + attr->activation_type = static_cast(actAttr.activationType); + + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetQuantDTypeCastPrimitive(const std::vector& primitive) +{ + QuantDTypeCast quantAttr; + auto ret = ParsePrimitive(primitive, quantAttr, QuantDTypeCastBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of QuantDTypeCast operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_QuantDTypeCast; + + auto attr = new (std::nothrow) mindspore::schema::QuantDTypeCastT; + if (attr == nullptr) { + HDF_LOGE("Create QuantDTypeCast primitive failed."); + return nullptr; + } + + attr->src_t = quantAttr.srcT; + attr->dst_t = quantAttr.dstT; + prim->value.value = attr; + return prim; +} + +PrimUniquePtr GetMulFusionPrimitive(const std::vector& primitive) +{ + MulFusion mulAttr; + auto ret = ParsePrimitive(primitive, mulAttr, MulFusionBlockUnmarshalling); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse primitive data of MulFusion operator failed."); + return nullptr; + } + + auto prim = std::make_unique(); + prim->value.type = mindspore::schema::PrimitiveType_MulFusion; + + auto attr = new (std::nothrow) mindspore::schema::MulFusionT; + if (attr == nullptr) { + HDF_LOGE("Create MulFusion primitive failed."); + return nullptr; + } + + attr->activation_type = static_cast(mulAttr.activationType); + prim->value.value = attr; + return prim; +} + +REGISTER_NODE(Activation, NodeType::NODE_TYPE_ACTIVATION, GetActivationPrimitive); +REGISTER_NODE(AddFusion, NodeType::NODE_TYPE_ADD_FUSION, GetAddPrimitive); +REGISTER_NODE(AvgPoolFusion, NodeType::NODE_TYPE_AVGPOOL_FUSION, GetAvgPoolPrimitive); +REGISTER_NODE(Concat, NodeType::NODE_TYPE_CONCAT, GetConcatPrimitive); +REGISTER_NODE(Conv2DFusion, NodeType::NODE_TYPE_CONV2D_FUSION, GetConv2dPrimitive); +REGISTER_NODE(FullConnection, NodeType::NODE_TYPE_FULL_CONNECTION, GetFullConnectionPrimitive); +REGISTER_NODE(MaxPoolFusion, NodeType::NODE_TYPE_MAX_POOL_FUSION, GetMaxPoolFusionPrimitive); +REGISTER_NODE(MatMulFusion, NodeType::NODE_TYPE_MATMUL_FUSION, GetMatMulFusionPrimitive); +REGISTER_NODE(Reshape, NodeType::NODE_TYPE_RESHAPE, GetReshapePrimitive); +REGISTER_NODE(Softmax, NodeType::NODE_TYPE_SOFTMAX, GetSoftmaxPrimitive); +REGISTER_NODE(ScaleFusion, NodeType::NODE_TYPE_SCALE_FUSION, GetScaleFusionPrimitive); +REGISTER_NODE(QuantDTypeCast, NodeType::NODE_TYPE_QUANT_DTYPE_CAST, GetQuantDTypeCastPrimitive); +REGISTER_NODE(MulFusion, NodeType::NODE_TYPE_MUL_FUSION, GetMulFusionPrimitive); +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_registry.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_registry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6537ad0d64ed53d6b9db2a37153e9d140125b9b --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/node_registry.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "node_registry.h" + +#include "hdf_log.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +NodeRegistry& NodeRegistry::GetSingleton() +{ + static NodeRegistry registry; + return registry; +} + +NodeRegistry::Registrar::Registrar(NodeType type, std::function&)> nodeFunc) +{ + auto& registry = NodeRegistry::GetSingleton(); + if (registry.m_nodeRegs.find(type) != registry.m_nodeRegs.end()) { + HDF_LOGW("Node has been registered. nodeType=%d", type); + } else { + registry.m_nodeRegs[type] = nodeFunc; + } +} + +std::function&)> NodeRegistry::GetNodeFunc(NodeType type) const +{ + if (m_nodeRegs.find(type) == m_nodeRegs.end()) { + HDF_LOGW("Node type is not found. nodeType=%d", type); + return nullptr; + } + + return m_nodeRegs.at(type); +} + +bool NodeRegistry::IsNodeTypeExist(NodeType type) const +{ + if (m_nodeRegs.find(type) == m_nodeRegs.end()) { + return false; + } + return true; +} +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/prepared_model_service.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/prepared_model_service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d3edf6ec2e066d144ce079573c1ba838ebb50d5 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/prepared_model_service.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "prepared_model_service.h" + +#include +#include "securec.h" +#include "hdf_log.h" + +#include "shared_buffer_parser.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +PreparedModelService::PreparedModelService(std::shared_ptr context) + : m_context(context) {} + +PreparedModelService::~PreparedModelService() +{ + if (m_cacheBuffer != nullptr) { + m_cacheBuffer->CloseAshmem(); + } + + for (auto& inputAsh : m_inputAshmems) { + inputAsh->UnmapAshmem(); + inputAsh->CloseAshmem(); + } + + for (auto& outputAsh : m_outputAshmems) { + outputAsh->UnmapAshmem(); + outputAsh->CloseAshmem(); + } +} + +int32_t PreparedModelService::ExportModelCache(std::vector& modelCache) +{ + if (!modelCache.empty()) { + HDF_LOGE("The parameters of ExportModelCache should be an empty vector."); + return HDF_ERR_INVALID_PARAM; + } + + if (m_cacheBuffer != nullptr) { + auto fd = m_cacheBuffer->GetAshmemFd(); + auto size = m_cacheBuffer->GetAshmemSize(); + + // SharedBuffer: fd, bufferSize, offset, dataSize + modelCache.emplace_back(SharedBuffer{fd, size, 0, size}); + return HDF_SUCCESS; + } + + auto size = m_builder.GetSize(); + auto buffer = m_builder.GetBufferPointer(); + const char* name = m_graph != nullptr ? m_graph->name.c_str() : "CacheModel"; + sptr cache = Ashmem::CreateAshmem(name, size); + if (cache == nullptr) { + HDF_LOGE("Create shared memory failed."); + return HDF_ERR_MALLOC_FAIL; + } + + bool ret = cache->MapReadAndWriteAshmem(); + if (!ret) { + HDF_LOGE("Map fd to write cache failed."); + return HDF_FAILURE; + } + + ret = cache->WriteToAshmem(buffer, size, 0); + cache->UnmapAshmem(); + if (!ret) { + HDF_LOGE("Write cache failed."); + return HDF_FAILURE; + } + + m_cacheBuffer = cache; + + // SharedBuffer: fd, bufferSize, offset, dataSize + modelCache.emplace_back(SharedBuffer {cache->GetAshmemFd(), cache->GetAshmemSize(), 0, cache->GetAshmemSize()}); + return HDF_SUCCESS; +} + +int32_t PreparedModelService::Run(const std::vector& inputs, const std::vector& outputs, + std::vector>& outputsDims, std::vector& isOutputBufferEnough) +{ + auto ret = SetInputs(inputs); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Inputs tensor is invalid."); + return ret; + } + + if (!m_isDynamicShape) { + ret = SetOutputs(outputs); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Output tensor is invalid."); + ResetInputAndOutput(); + return ret; + } + } + + auto msRet = m_model->Predict(m_inputs, &m_outputs); + if (msRet != mindspore::kSuccess) { + HDF_LOGE("Run model failed."); + ResetInputAndOutput(); + return HDF_FAILURE; + } + + ret = UpdateOutput(outputs, outputsDims, isOutputBufferEnough); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Update output dimension or data failed."); + ResetInputAndOutput(); + return ret; + } + + ResetInputAndOutput(); + + return HDF_SUCCESS; +} + +int32_t PreparedModelService::GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims) +{ + if (m_inputDims.empty()) { + HDF_LOGE("Model has not been prepared yet."); + return HDF_ERR_INVALID_PARAM; + } + + minInputDims.clear(); + maxInputDims.clear(); + + for (auto inputShape : m_inputDims) { + std::vector minInputShape; + std::vector maxInputShape; + for (auto dim : inputShape) { + if (dim != DYNAMIC_SHAPE_FLAG) { // Min and max are same if the dimension is fixed. + if (dim <= 0) { + HDF_LOGE("Dimesion value is invalid."); + return HDF_ERR_INVALID_PARAM; + } + minInputShape.push_back(static_cast(dim)); + maxInputShape.push_back(static_cast(dim)); + } else { // Dimension range is [1, 10]. + minInputShape.push_back(1); + maxInputShape.push_back(10); + } + } + minInputDims.push_back(std::move(minInputShape)); + maxInputDims.push_back(std::move(maxInputShape)); + } + + return HDF_SUCCESS; +} + +int32_t PreparedModelService::UpdateOutput(const std::vector& outputs, + std::vector>& outputsDims, std::vector& isOutputBufferEnough) +{ + bool isEnough {true}; + size_t outputSize = m_outputs.size(); + isOutputBufferEnough.resize(outputSize, true); + for (size_t i = 0; i < outputSize; i++) { + auto& msOutput = m_outputs[i]; + auto& output = outputs[i]; + + auto msShape = msOutput.Shape(); + outputsDims.emplace_back(msShape.begin(), msShape.end()); + + auto dataSize = msOutput.DataSize(); + if (dataSize > output.data.bufferSize) { + HDF_LOGE("Output buffer is not enough. actual size %{public}zu, buffer size %{public}u", + dataSize, output.data.bufferSize); + isOutputBufferEnough[i] = false; + isEnough= false; + } + + if (isEnough && m_isDynamicShape) { + auto msData = msOutput.MutableData(); + SharedBufferParser parser; + auto ret = parser.Init(output.data); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Parse %zu th output data failed.", i); + return HDF_ERR_INVALID_PARAM; + } + + auto data = parser.GetBufferPtr(); + auto memRet = memcpy_s(data, dataSize, msData, dataSize); + if (memRet != EOK) { + HDF_LOGE("Copy output memory failed."); + return HDF_FAILURE; + } + } + } + + return HDF_SUCCESS; +} + +void PreparedModelService::ResetInputAndOutput() +{ + for (auto& msInput : m_inputs) { + msInput.SetData(nullptr); + } + + if (!m_isDynamicShape) { + for (auto& msOutput : m_outputs) { + msOutput.SetData(nullptr); + } + } +} + +int32_t PreparedModelService::Compile(std::shared_ptr graph) +{ + if (graph == nullptr) { + HDF_LOGE("Graph cannot be nullptr"); + return HDF_ERR_INVALID_PARAM; + } + for (auto i : graph->inputIndex) { + auto inputShape = graph->allTensors[i]->dims; + auto iter = std::find(inputShape.begin(), inputShape.end(), DYNAMIC_SHAPE_FLAG); + if (iter != inputShape.end()) { + m_isDynamicShape = true; + break; + } + } + auto offset = mindspore::schema::MetaGraph::Pack(m_builder, graph.get()); + m_builder.Finish(offset); + mindspore::schema::FinishMetaGraphBuffer(m_builder, offset); + auto modelSize = m_builder.GetSize(); + uint8_t* modelBuffer = m_builder.GetBufferPointer(); + if (modelBuffer == nullptr) { + HDF_LOGE("Model is invalid."); + return HDF_FAILURE; + } + + m_model = std::make_shared(); + mindspore::Status msRet = m_model->Build(modelBuffer, modelSize, mindspore::kMindIR, m_context); + if (msRet != mindspore::kSuccess) { + HDF_LOGE("Prepare model failed, please make sure model is validate."); + return HDF_FAILURE; + } + + auto ret = GetMSInputsAndOutputs(); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Model without inputs or outputs is invalid."); + return ret; + } + + for (auto input : m_inputs) { + m_inputDims.push_back(input.Shape()); + } + + return HDF_SUCCESS; +} + +int32_t PreparedModelService::Compile(const void* modelBuffer, size_t length) +{ + if (modelBuffer == nullptr || length == 0) { + HDF_LOGE("ModelBuffer cannot be nullptr and length cannot be zero."); + return HDF_ERR_INVALID_PARAM; + } + + m_model = std::make_shared(); + mindspore::Status msRet = m_model->Build(modelBuffer, length, mindspore::kMindIR, m_context); + if (msRet != mindspore::kSuccess) { + HDF_LOGE("Prepare model from cache failed, please make sure model cache is valid."); + return HDF_FAILURE; + } + + auto ret = GetMSInputsAndOutputs(); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Model without inputs or outputs is invalid."); + return ret; + } + + for (auto input : m_inputs) { + auto shapes = input.Shape(); + if (std::find(shapes.begin(), shapes.end(), DYNAMIC_SHAPE_FLAG) != shapes.end()) { + m_isDynamicShape = true; + break; + } + } + + for (auto input : m_inputs) { + m_inputDims.push_back(input.Shape()); + } + + return HDF_SUCCESS; +} + +int32_t PreparedModelService::SetInputs(const std::vector& inputs) +{ + if (inputs.size() != m_inputs.size()) { + HDF_LOGE("inputs size is invalid. expect: %zu, actual: %zu", m_inputs.size(), inputs.size()); + return HDF_ERR_INVALID_PARAM; + } + for (auto& ash : m_inputAshmems) { + ash->UnmapAshmem(); + ash->CloseAshmem(); + } + m_inputAshmems.clear(); + + int32_t ret {0}; + size_t inputSize = m_inputs.size(); + std::vector> tmpAllDims; + for (size_t i = 0; i < inputSize; i++) { + auto& input = inputs[i]; + auto& msInput = m_inputs[i]; + ret = CompareTensor(input, msInput); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Inputs tensor is not match that of model. Please check input tensor."); + return ret; + } + tmpAllDims.emplace_back(input.dimensions.begin(), input.dimensions.end()); + } + + if (m_isDynamicShape) { + auto msRet = m_model->Resize(m_inputs, tmpAllDims); + if (msRet != mindspore::kSuccess) { + HDF_LOGE("Resize for dynamic inputs failed."); + return HDF_FAILURE; + } + ret = GetMSInputsAndOutputs(); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Get ms inputs or outputs failed after resize."); + return ret; + } + } + + for (size_t i = 0; i < inputSize; i++) { + auto& input = inputs[i]; + auto& msInput = m_inputs[i]; + sptr ashptr = ParseBuffer(input.data); + if (ashptr == nullptr) { + HDF_LOGE("Parse %zuth input data failed.", i); + return HDF_ERR_INVALID_PARAM; + } + + auto data = const_cast(ashptr->ReadFromAshmem(input.data.dataSize, 0)); + msInput.SetData(data); + m_inputAshmems.emplace_back(ashptr); + } + return HDF_SUCCESS; +} + +int32_t PreparedModelService::SetOutputs(const std::vector& outputs) +{ + HDF_LOGI("Start Set outputs, m_outputs size=%zu", m_outputs.size()); + if (outputs.size() != m_outputs.size()) { + HDF_LOGE("outputs size is invalid. expect: %{public}zu, actual: %{public}zu", m_outputs.size(), outputs.size()); + return HDF_ERR_INVALID_PARAM; + } + for (auto ash : m_outputAshmems) { + ash->UnmapAshmem(); + ash->CloseAshmem(); + } + m_outputAshmems.clear(); + + for (size_t i = 0; i < m_outputs.size(); i++) { + auto& output = outputs[i]; + auto& msOutput = m_outputs[i]; + + sptr ashptr = ParseBuffer(output.data); + if (ashptr == nullptr) { + HDF_LOGE("Parse %{public}zu th output data failed.", i); + return HDF_ERR_INVALID_PARAM; + } + + auto data = const_cast(ashptr->ReadFromAshmem(output.data.dataSize, 0)); + msOutput.SetAllocator(nullptr); + msOutput.SetData(data); + m_outputAshmems.emplace_back(ashptr); + } + return HDF_SUCCESS; +} + +int32_t PreparedModelService::GetMSInputsAndOutputs() +{ + m_inputs = m_model->GetInputs(); + if (m_inputs.empty()) { + HDF_LOGE("Get inputs failed."); + return HDF_FAILURE; + } + + m_outputs = m_model->GetOutputs(); + if (m_outputs.empty()) { + HDF_LOGE("Get outputs failed."); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t PreparedModelService::CompareTensor(const IOTensor& tensor, const mindspore::MSTensor& msTensor) +{ + auto dataType = static_cast(msTensor.DataType()); + if (tensor.dataType != dataType) { + HDF_LOGE("Data type of tensor dose not match that of model."); + return HDF_ERR_INVALID_PARAM; + } + + auto format = static_cast(msTensor.format()); + if (tensor.format != format) { + HDF_LOGE("Format of tensor dose not match that of model."); + return HDF_ERR_INVALID_PARAM; + } + + if (tensor.dimensions.size() != msTensor.Shape().size()) { + HDF_LOGE("Rank of tensor dose not match that of model."); + return HDF_ERR_INVALID_PARAM; + } + + for (size_t i = 0; i < tensor.dimensions.size(); i++) { + if (msTensor.Shape()[i] != DYNAMIC_SHAPE_FLAG && tensor.dimensions[i] != msTensor.Shape()[i]) { + HDF_LOGE("The Shape of tensor dose not match that of model."); + return HDF_ERR_INVALID_PARAM; + } + } + + return HDF_SUCCESS; +} + +sptr PreparedModelService::ParseBuffer(const SharedBuffer& buffer) +{ + if (buffer.fd == -1) { + HDF_LOGE("Invalid buffer fd, it cannot be -1."); + return nullptr; + } + + HDF_LOGW("NNRT buffer fd=%{public}d, length=%{public}u", buffer.fd, buffer.dataSize); + + sptr ashptr = new (std::nothrow) Ashmem(buffer.fd, buffer.bufferSize); + if (ashptr == nullptr) { + HDF_LOGE("Create shared memory failed."); + return nullptr; + } + + if (!ashptr->MapReadAndWriteAshmem()) { + HDF_LOGE("Map buffer fd to address failed."); + return nullptr; + } + + const void* data = ashptr->ReadFromAshmem(buffer.dataSize, buffer.offset); + if (data == nullptr) { + HDF_LOGE("Get data address failed."); + ashptr->UnmapAshmem(); + ashptr->CloseAshmem(); + return nullptr; + } + return ashptr; +} +} // V2_0 +} // Nnrt +} // HDI +} // OHOS diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/shared_buffer_parser.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/shared_buffer_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69416b69342d939bb00d8ce3eebb498133d66a8f --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/shared_buffer_parser.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 OHOS_HDI_NNR_V2_0_UTILS_H +#define OHOS_HDI_NNR_V2_0_UTILS_H + +#include "shared_buffer_parser.h" + +#include +#include "ashmem.h" +#include "v2_0/nnrt_types.h" +#include "hdf_log.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +SharedBufferParser::~SharedBufferParser() +{ + if (m_ashptr != nullptr) { + m_ashptr->UnmapAshmem(); + m_ashptr->CloseAshmem(); + m_bufferAddr = nullptr; + } +} + +int32_t SharedBufferParser::Init(const std::string& name, int32_t size) +{ + HDF_LOGI("Init SharedBufferParser from name and size."); + sptr ashptr = Ashmem::CreateAshmem(name.c_str(), size); + if (ashptr == nullptr) { + HDF_LOGE("Create ashmen from size failed."); + return HDF_FAILURE; + } + + SharedBuffer buffer; + buffer.fd = ashptr->GetAshmemFd(); + buffer.bufferSize = ashptr->GetAshmemSize(); + buffer.offset = 0; + buffer.dataSize = size; + + auto ret = Init(buffer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Init SharedBufferParser failed."); + return ret; + } + return HDF_SUCCESS; +} + +int32_t SharedBufferParser::Init(const SharedBuffer& buffer) +{ + if (buffer.fd == INVALID_FD) { + HDF_LOGE("Invalid buffer fd, it cannot be %{public}d.", INVALID_FD); + return HDF_ERR_INVALID_PARAM; + } + + m_ashptr = new (std::nothrow) Ashmem(buffer.fd, buffer.bufferSize); + if (m_ashptr == nullptr) { + HDF_LOGE("Create ashmem failed."); + return HDF_FAILURE; + } + + if (!m_ashptr->MapReadAndWriteAshmem()) { + HDF_LOGE("Map buffer fd to address failed."); + return HDF_FAILURE; + } + + auto bufferAddr = m_ashptr->ReadFromAshmem(buffer.dataSize, buffer.offset); + if (bufferAddr == nullptr) { + HDF_LOGE("Invalid dataSize or offset of SharedBuffer."); + return HDF_ERR_INVALID_PARAM; + } + m_bufferAddr = const_cast(bufferAddr); + + m_buffer = buffer; + return HDF_SUCCESS; +} + +void* SharedBufferParser::GetBufferPtr() +{ + return m_bufferAddr; +} + +SharedBuffer SharedBufferParser::GetBuffer() +{ + return m_buffer; +} +} // V2_0 +} // Nnrt +} // HDI +} // OHOS +#endif // OHOS_HDI_NNR_V2_0_UTILS_H \ No newline at end of file diff --git a/example/drivers/nnrt/v2_0/hdi_cpu_service/src/validation.cpp b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/validation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03521c75dfa7a05dfe22d1e8d82f5864647a31f5 --- /dev/null +++ b/example/drivers/nnrt/v2_0/hdi_cpu_service/src/validation.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "validation.h" + +namespace OHOS { +namespace HDI { +namespace Nnrt { +namespace V2_0 { +int32_t ValidatePerformanceMode(PerformanceMode mode) +{ + if (mode < PerformanceMode::PERFORMANCE_NONE || mode > PerformanceMode::PERFORMANCE_EXTREME) { + return false; + } + + return true; +} + +int32_t ValidatePriority(Priority priority) +{ + if (priority < Priority::PRIORITY_NONE || priority > Priority::PRIORITY_HIGH) { + return false; + } + + return true; +} + +int32_t ValidateDataType(DataType dataType) +{ + if (dataType < DataType::DATA_TYPE_UNKNOWN || dataType > DataType::DATA_TYPE_FLOAT64) { + return false; + } + + if (dataType > DataType::DATA_TYPE_UNKNOWN && dataType < DataType::DATA_TYPE_BOOL) { + return false; + } + + if (dataType > DataType::DATA_TYPE_BOOL && dataType < DataType::DATA_TYPE_INT8) { + return false; + } + + if (dataType > DataType::DATA_TYPE_UINT64 && dataType < DataType::DATA_TYPE_FLOAT16) { + return false; + } + + return true; +} + +int32_t ValidateFormat(Format format) +{ + if (format < Format::FORMAT_NONE || format > Format::FORMAT_NHWC) { + return false; + } + + return true; +} +} // namespace V2_0 +} // namespace Nnrt +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/BUILD.gn b/frameworks/BUILD.gn index 321fb2f9e1c5e4c8319eca89ca275ef9dd641ad6..bc88015744b6ff42ad26144168a291a1dc3e8af2 100644 --- a/frameworks/BUILD.gn +++ b/frameworks/BUILD.gn @@ -23,8 +23,13 @@ nnrt_sources = [ "native/device_registrar.cpp", "native/execution_plan.cpp", "native/executor.cpp", - "native/hdi_device.cpp", - "native/hdi_prepared_model.cpp", + "native/device_discover_v1_0.cpp", + "native/device_discover_v2_0.cpp", + "native/hdi_device_v1_0.cpp", + "native/hdi_device_v2_0.cpp", + "native/hdi_prepared_model_v1_0.cpp", + "native/hdi_prepared_model_v2_0.cpp", + "native/hdi_returncode_transform.cpp", "native/inner_model.cpp", "native/memory_manager.cpp", "native/neural_network_runtime.cpp", @@ -122,6 +127,7 @@ ohos_shared_library("libneural_network_runtime") { external_deps = [ "c_utils:utils", "drivers_interface_nnrt:libnnrt_proxy_1.0", + "drivers_interface_nnrt:libnnrt_proxy_2.0", "hdf_core:libhdf_utils", "hilog_native:libhilog", "hitrace_native:libhitracechain", diff --git a/frameworks/native/compilation.cpp b/frameworks/native/compilation.cpp index ed6e737ba4124bd8387ae3a2be9e6af35dee69b8..c259932fb76e1870299b18e6cfc12c8e43c45d9b 100644 --- a/frameworks/native/compilation.cpp +++ b/frameworks/native/compilation.cpp @@ -607,6 +607,26 @@ OH_NN_ReturnCode Compilation::InnerBuild() { OH_NN_ReturnCode ret; std::shared_ptr preparedModel; + + // Prepare from offline model. + bool isOfflineModel{false}; + ret = IsOfflineModel(isOfflineModel); + if (ret != OH_NN_SUCCESS) { + LOGE("[Compilation] Failed when identifying the offline model."); + return ret; + } + + if (isOfflineModel) { + ret = BuildOfflineModel(preparedModel); + if (ret != OH_NN_SUCCESS) { + LOGE("[Compilation] Failed to build offline model."); + return ret; + } + + m_isBuild = true; + return OH_NN_SUCCESS; + } + if (m_cachePath.empty()) { ret = NormalBuild(preparedModel); if (ret != OH_NN_SUCCESS) { @@ -710,5 +730,56 @@ bool Compilation::IsDynamicShape() const } return false; } + +OH_NN_ReturnCode Compilation::IsOfflineModel(bool& isOfflineModel) const +{ + isOfflineModel = false; // Initialize the returned value + if (m_liteGraph == nullptr) { + LOGE("[Compilation] LiteGraph is empty when identifying the offline model."); + return OH_NN_NULL_PTR; + } + + if (m_liteGraph->all_nodes_.size() == 0) { + LOGE("[Compilation] Find empty node in the model."); + return OH_NN_INVALID_PARAMETER; + } + + // If the model consists of more than 1 node, it will not be considered as offline model. + if (m_liteGraph->all_nodes_.size() > 1) { + isOfflineModel = false; + return OH_NN_SUCCESS; + } + + const mindspore::lite::LiteGraph::Node* pNode = m_liteGraph->all_nodes_[0]; + if (pNode == nullptr) { + LOGE("[Compilation] Find invalid node in the model."); + return OH_NN_NULL_PTR; + } + + const mindspore::lite::NodeType& nodeType = mindspore::lite::MindIR_Primitive_GetType(pNode->primitive_); + if (nodeType == mindspore::lite::NodeType::NODE_TYPE_CUSTOM) { + isOfflineModel = true; + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode Compilation::BuildOfflineModel(std::shared_ptr& preparedModel) +{ + ModelConfig config {m_enableFp16, m_performance, m_priority}; + OH_NN_ReturnCode ret = m_device->PrepareOfflineModel(m_liteGraph, config, preparedModel); + if (ret != OH_NN_SUCCESS) { + LOGE("[Compilation] Preparing model failed when building from offline model."); + return ret; + } + + m_executionPlan = CreateSharedPtr(preparedModel, m_device); + if (m_executionPlan == nullptr) { + LOGE("[Compilation] Failed to create ExecutionPlan when building from offline model."); + return OH_NN_MEMORY_ERROR; + } + + return OH_NN_SUCCESS; +} } // namespace NeuralNetworkRuntime } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/compilation.h b/frameworks/native/compilation.h index a85f6a50294257721020dfd91c0ba68de598395f..3d81fe9e0a89a3330db40c6c180998cc5db02697 100644 --- a/frameworks/native/compilation.h +++ b/frameworks/native/compilation.h @@ -79,6 +79,8 @@ private: OH_NN_ReturnCode LoadCacheBuild(std::shared_ptr& preparedModel, const ModelCacheInfo& cacheInfo); OH_NN_ReturnCode InnerBuild(); OH_NN_ReturnCode GetCacheFileLength(std::ifstream& ifs, int& fsize) const; + OH_NN_ReturnCode IsOfflineModel(bool& isOfflineModel) const; + OH_NN_ReturnCode BuildOfflineModel(std::shared_ptr& preparedModel); }; } // namespace NeuralNetworkRuntime } // namespace OHOS diff --git a/frameworks/native/device.h b/frameworks/native/device.h index 93415e4bb527e26049cba0563cc3e86bcfa4b148..bc0989fbba31df46a5692512434d4305299c5b07 100644 --- a/frameworks/native/device.h +++ b/frameworks/native/device.h @@ -34,6 +34,7 @@ public: virtual OH_NN_ReturnCode GetDeviceName(std::string& name) = 0; virtual OH_NN_ReturnCode GetVendorName(std::string& name) = 0; + virtual OH_NN_ReturnCode GetVersion(std::string& version) = 0; virtual OH_NN_ReturnCode GetDeviceType(OH_NN_DeviceType& deviceType) = 0; virtual OH_NN_ReturnCode GetDeviceStatus(DeviceStatus& status) = 0; virtual OH_NN_ReturnCode GetSupportedOperation(std::shared_ptr model, @@ -51,6 +52,10 @@ public: virtual OH_NN_ReturnCode PrepareModelFromModelCache(const std::vector& modelCache, const ModelConfig& config, std::shared_ptr& preparedModel) = 0; + virtual OH_NN_ReturnCode PrepareOfflineModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) = 0; + virtual void* AllocateBuffer(size_t length) = 0; virtual OH_NN_ReturnCode ReleaseBuffer(const void* buffer) = 0; diff --git a/frameworks/native/device_discover.h b/frameworks/native/device_discover.h new file mode 100644 index 0000000000000000000000000000000000000000..fd86f1fa069076f6f832ecab8c1d1d27ac7a87e7 --- /dev/null +++ b/frameworks/native/device_discover.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 NEURAL_NETWORK_RUNTIME_DEVICE_DISCOVER_H +#define NEURAL_NETWORK_RUNTIME_DEVICE_DISCOVER_H + +#include +#include + +#include "device.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { +std::shared_ptr DiscoverHDIDevicesV1_0(std::string& deviceName, std::string& vendorName, std::string& version); +std::shared_ptr DiscoverHDIDevicesV2_0(std::string& deviceName, std::string& vendorName, std::string& version); + +} // namespace NeuralNetworkRuntime +} // namespace OHOS +#endif // NEURAL_NETWORK_RUNTIME_DEVICE_DISCOVER_H \ No newline at end of file diff --git a/frameworks/native/device_discover_v1_0.cpp b/frameworks/native/device_discover_v1_0.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5f802e9d086d61d545320bcb490e7c15f7058d2 --- /dev/null +++ b/frameworks/native/device_discover_v1_0.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "device_discover.h" +#include "hdi_device_v1_0.h" +#include "common/log.h" +#include "common/utils.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { +std::shared_ptr DiscoverHDIDevicesV1_0(std::string& deviceName, std::string& vendorName, std::string& version) +{ + // only one device from HDI now. + OHOS::sptr iDevice = V1_0::INnrtDevice::Get(); + if (iDevice == nullptr) { + LOGW("Get HDI device failed."); + return nullptr; + } + + auto hdiRet = iDevice->GetDeviceName(deviceName); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get device name failed. ErrorCode=%d", hdiRet); + return nullptr; + } + hdiRet = iDevice->GetVendorName(vendorName); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get vendor name failed. ErrorCode=%d", hdiRet); + return nullptr; + } + std::pair hdiVersion; + hdiRet = iDevice->GetVersion(hdiVersion.first, hdiVersion.second); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get version failed. ErrorCode=%d", hdiRet); + return nullptr; + } + version = 'v' + std::to_string(hdiVersion.first) + '_' + std::to_string(hdiVersion.second); + + std::shared_ptr device = CreateSharedPtr(iDevice); + if (device == nullptr) { + LOGW("Failed to register device, because fail to create device instance."); + } + return device; +} +} // namespace NeuralNetworkRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/device_discover_v2_0.cpp b/frameworks/native/device_discover_v2_0.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4a1cac26ac8b848db214b2555dc6618106a5232 --- /dev/null +++ b/frameworks/native/device_discover_v2_0.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "device_discover.h" +#include "hdi_device_v2_0.h" +#include "hdi_returncode_transform.h" +#include "common/log.h" +#include "common/utils.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { +std::shared_ptr DiscoverHDIDevicesV2_0(std::string& deviceName, std::string& vendorName, std::string& version) +{ + // only one device from HDI now. + OHOS::sptr iDevice = V2_0::INnrtDevice::Get(); + if (iDevice == nullptr) { + LOGW("Get HDI device failed."); + return nullptr; + } + + V2_0::NNRT_ReturnCode returnCode; + auto hdiRet = iDevice->GetDeviceName(deviceName, returnCode); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get device name failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + hdiRet, ConverterRetToString(returnCode).c_str()); + return nullptr; + } + hdiRet = iDevice->GetVendorName(vendorName, returnCode); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get vendor name failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + hdiRet, ConverterRetToString(returnCode).c_str()); + return nullptr; + } + std::pair hdiVersion; + hdiRet = iDevice->GetVersion(hdiVersion.first, hdiVersion.second); + if (hdiRet != HDF_SUCCESS) { + LOGW("Get version failed. ErrorCode=%{public}d", hdiRet); + return nullptr; + } + version = 'v' + std::to_string(hdiVersion.first) + '_' + std::to_string(hdiVersion.second); + + std::shared_ptr device = CreateSharedPtr(iDevice); + if (device == nullptr) { + LOGW("Failed to register device, because fail to create device instance."); + } + return device; +} +} // namespace NeuralNetworkRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/device_manager.cpp b/frameworks/native/device_manager.cpp index 6ad79bbc5ffe954305079386c3e6c42c1dcacd85..75ac674f3e2dd3ec9e7ae9bc0ab2e96b79bcfde9 100644 --- a/frameworks/native/device_manager.cpp +++ b/frameworks/native/device_manager.cpp @@ -14,9 +14,8 @@ */ #include "device_manager.h" +#include "device_discover.h" -#include "hdi_interfaces.h" -#include "hdi_device.h" #include "common/log.h" #include "common/utils.h" @@ -70,13 +69,21 @@ const std::string& DeviceManager::GetDeviceName(size_t deviceId) return m_tmpDeviceName; } - m_tmpDeviceName = GenUniqueName(deviceName, vendorName); + std::string version; + ret = iter->second->GetVersion(version); + if (ret != OH_NN_SUCCESS) { + LOGE("Get version failed."); + return m_tmpDeviceName; + } + + m_tmpDeviceName = GenUniqueName(deviceName, vendorName, version); return m_tmpDeviceName; } -std::string DeviceManager::GenUniqueName(const std::string& deviceName, const std::string& vendorName) const +std::string DeviceManager::GenUniqueName( + const std::string& deviceName, const std::string& vendorName, const std::string& version) const { - return deviceName + "_" + vendorName; + return deviceName + "_" + vendorName + "_" + version; } OH_NN_ReturnCode DeviceManager::RegisterDevice(std::function()> creator) @@ -106,8 +113,15 @@ OH_NN_ReturnCode DeviceManager::RegisterDevice(std::functionGetVersion(version); + if (ret != OH_NN_SUCCESS) { + LOGE("Get version failed."); + return ret; + } + const std::lock_guard lock(m_mtx); - std::string uniqueName = GenUniqueName(deviceName, vendorName); + std::string uniqueName = GenUniqueName(deviceName, vendorName, version); auto setResult = m_uniqueName.emplace(uniqueName); if (!setResult.second) { LOGE("Device already exists, cannot register again. deviceName=%s, vendorName=%s", @@ -119,29 +133,10 @@ OH_NN_ReturnCode DeviceManager::RegisterDevice(std::function device) { - // only one device from HDI now. - OHOS::sptr iDevice = V1_0::INnrtDevice::Get(); - if (iDevice == nullptr) { - LOGW("Get HDI device failed."); - return; - } - - std::string deviceName; - std::string vendorName; - auto hdiRet = iDevice->GetDeviceName(deviceName); - if (hdiRet != HDF_SUCCESS) { - LOGW("Get device name failed. ErrorCode=%d", hdiRet); - return; - } - hdiRet = iDevice->GetVendorName(vendorName); - if (hdiRet != HDF_SUCCESS) { - LOGW("Get vendor name failed. ErrorCode=%d", hdiRet); - return; - } - - std::string uniqueName = GenUniqueName(deviceName, vendorName); + std::string uniqueName = GenUniqueName(deviceName, vendorName, version); const std::lock_guard lock(m_mtx); auto setResult = m_uniqueName.emplace(uniqueName); if (!setResult.second) { @@ -150,14 +145,25 @@ void DeviceManager::DiscoverHDIDevices() return; } - std::shared_ptr device = CreateSharedPtr(iDevice); - if (device == nullptr) { - LOGW("Failed to register device, because fail to create device instance."); - return; - } m_devices.emplace(std::hash{}(uniqueName), device); } +void DeviceManager::DiscoverHDIDevices() +{ + std::string deviceName; + std::string vendorName; + std::string version; + std::shared_ptr deviceV1_0 = DiscoverHDIDevicesV1_0(deviceName, vendorName, version); + if (deviceV1_0 != nullptr) { + AddDevice(deviceName, vendorName, version, deviceV1_0); + } + + std::shared_ptr deviceV2_0 = DiscoverHDIDevicesV2_0(deviceName, vendorName, version); + if (deviceV2_0 != nullptr) { + AddDevice(deviceName, vendorName, version, deviceV2_0); + } +} + bool DeviceManager::IsValidDevice(std::shared_ptr device) const { DeviceStatus status {DeviceStatus::UNKNOWN}; diff --git a/frameworks/native/device_manager.h b/frameworks/native/device_manager.h index 20d4bf05834c6cbac02191ffa1f743730ebbfb9e..4d8b9fbd35e1c029c9c8ab46c6a620ce12c63ed6 100644 --- a/frameworks/native/device_manager.h +++ b/frameworks/native/device_manager.h @@ -49,8 +49,11 @@ private: DeviceManager(const DeviceManager&) = delete; DeviceManager& operator=(const DeviceManager&) = delete; + void AddDevice(const std::string& deviceName, const std::string& vendorName, + const std::string& version, std::shared_ptr device); void DiscoverHDIDevices(); - std::string GenUniqueName(const std::string& deviceName, const std::string& vendorName) const; + std::string GenUniqueName( + const std::string& deviceName, const std::string& vendorName, const std::string& version) const; bool IsValidDevice(std::shared_ptr device) const; private: diff --git a/frameworks/native/device_registrar.h b/frameworks/native/device_registrar.h index a9645299821087407c45202087110eca1b8365ea..521a075a336db601d839d10eafe5ca1455c0ca34 100644 --- a/frameworks/native/device_registrar.h +++ b/frameworks/native/device_registrar.h @@ -34,7 +34,7 @@ public: #define REGISTER_DEVICE(deviceName, vendorName, creator) \ namespace { \ - static OHOS::NeuralNetworkRuntime::DeviceRegistrar g_##deviceName##_##vendorName##_device_registrar(creator) \ + static OHOS::NeuralNetworkRuntime::DeviceRegistrar g_##deviceName##_##vendorName##_device_registrar(creator); \ } // namespace } // namespace NeuralNetworkRuntime } // OHOS diff --git a/frameworks/native/execution_plan.cpp b/frameworks/native/execution_plan.cpp index b1ddfe3ac53676fb016bd9aeebd9bd1deaabfd01..5199199bfd9cf4c11a8d0c58cddcfc2108743ead 100644 --- a/frameworks/native/execution_plan.cpp +++ b/frameworks/native/execution_plan.cpp @@ -23,6 +23,18 @@ namespace OHOS { namespace NeuralNetworkRuntime { +OH_NN_ReturnCode ExecutionPlan::GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims) +{ + OH_NN_ReturnCode ret = m_preparedModel->GetInputDimRanges(minInputDims, maxInputDims); + if (ret != OH_NN_SUCCESS) { + LOGE("ExecutionPlan GetInputDimRanges() failed."); + return ret; + } + + return OH_NN_SUCCESS; +} + OH_NN_ReturnCode ExecutionPlan::Run(const std::vector>& inputTensors, std::vector>& outputTensors) { diff --git a/frameworks/native/execution_plan.h b/frameworks/native/execution_plan.h index 9644a321d12b0120f24af6835e7eb035548c7445..54f4648b21372a1a23b6a9d7bef5dd0ec023e36b 100644 --- a/frameworks/native/execution_plan.h +++ b/frameworks/native/execution_plan.h @@ -29,6 +29,9 @@ public: ExecutionPlan(std::shared_ptr preparedModel, std::shared_ptr device) : m_preparedModel(preparedModel), m_device(device) {}; + + OH_NN_ReturnCode GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims); OH_NN_ReturnCode Run(const std::vector>& inputTensors, std::vector>& outputTensors); diff --git a/frameworks/native/executor.cpp b/frameworks/native/executor.cpp index f99d28cdb1869484968217fb5b03c927e6e7b3f7..93670eb0f715e6640e3e06588d034638a3404135 100644 --- a/frameworks/native/executor.cpp +++ b/frameworks/native/executor.cpp @@ -19,6 +19,7 @@ #include "common/utils.h" #include "common/scoped_trace.h" +#include "transform.h" namespace OHOS { @@ -113,8 +114,64 @@ void Executor::SetInputTensorWithNewBuffer(uint32_t index, } +OH_NN_ReturnCode Executor::CheckInputDimRanges(uint32_t index, const OH_NN_Tensor& nnTensor) const +{ + std::vector> minInputDims; + std::vector> maxInputDims; + auto ret = m_executionPlan->GetInputDimRanges(minInputDims, maxInputDims); + if (ret != OH_NN_SUCCESS) { + LOGE("Get the dimension ranges of input %u failed. ErrorCode=%d", index, ret); + return ret; + } + + if (index >= minInputDims.size()) { + LOGE("index is %u, which exceeds the size of minInputDims:%zu.", index, minInputDims.size()); + return OH_NN_INVALID_PARAMETER; + } + + if (index >= maxInputDims.size()) { + LOGE("index is %u, which exceeds the size of maxInputDims:%zu.", index, maxInputDims.size()); + return OH_NN_INVALID_PARAMETER; + } + + const std::vector& minSingleInputDims = minInputDims[index]; + const std::vector& maxSingleInputDims = maxInputDims[index]; + + std::vector tensorShape = ConstructVectorFromArray(nnTensor.dimensions, nnTensor.dimensionCount); + size_t tensorShapeSize = tensorShape.size(); + if (minSingleInputDims.size() != tensorShapeSize || maxSingleInputDims.size() != tensorShapeSize) { + LOGE("Size of minSingleInputDims, maxSingleInputDims and tensorShape of input %u are not equal.", index); + return OH_NN_INVALID_PARAMETER; + } + + for (size_t j = 0; j < tensorShapeSize; ++j) { + // Dimensions cannot be negative + if (tensorShape[j] < 0) { + LOGE("Dimension %zu of input %u is %d.", j, index, tensorShape[j]); + return OH_NN_INVALID_PARAMETER; + } + uint32_t dim = static_cast(tensorShape[j]); + if (dim < minSingleInputDims[j] || dim > maxSingleInputDims[j]) { + LOGE("Dimension %zu of input %u is %u, which is out of range [%u, %u]", + j, index, dim, minSingleInputDims[j], maxSingleInputDims[j]); + return OH_NN_INVALID_PARAMETER; + } + } + + return OH_NN_SUCCESS; +} + + OH_NN_ReturnCode Executor::SetInput(uint32_t index, const OH_NN_Tensor& nnTensor, const void* buffer, size_t length) { + auto nnRet = CheckInputDimRanges(index, nnTensor); + if (nnRet == OH_NN_OPERATION_FORBIDDEN) { + LOGI("Skip input dimension bounds check."); + } else if (nnRet != OH_NN_SUCCESS) { + LOGE("SetInput failed, Check the range of the %uth input dimension ranges failed.", index); + return nnRet; + } + std::shared_ptr inputTensor = CreateSharedPtr(); if (inputTensor == nullptr) { LOGE("SetInput failed, error happened when creating NNTensor."); @@ -181,6 +238,14 @@ OH_NN_ReturnCode Executor::SetInput(uint32_t index, const OH_NN_Tensor& nnTensor OH_NN_ReturnCode Executor::SetInputFromMemory(uint32_t index, const OH_NN_Tensor& nnTensor, const OH_NN_Memory& memory) { + auto nnRet = CheckInputDimRanges(index, nnTensor); + if (nnRet == OH_NN_OPERATION_FORBIDDEN) { + LOGI("Skip input dimension bounds check."); + } else if (nnRet != OH_NN_SUCCESS) { + LOGE("SetInputFromMemory failed, Check the range of the %uth input dimension ranges failed.", index); + return nnRet; + } + // Build a input tensor std::shared_ptr inputTensor = CreateSharedPtr(); if (inputTensor == nullptr) { diff --git a/frameworks/native/executor.h b/frameworks/native/executor.h index f7a98eb094f35c4235e8f04b5d92e9746f7dff63..c7b2061e911800cef2efcf80bbec771e9b50b6dd 100644 --- a/frameworks/native/executor.h +++ b/frameworks/native/executor.h @@ -49,6 +49,7 @@ private: const void* buffer, size_t dataLength, size_t curBufferLength); void SetInputTensorWithNewBuffer(uint32_t index, std::shared_ptr inputTensor, const void* inputBuffer, size_t length, bool isInnerMem); + OH_NN_ReturnCode CheckInputDimRanges(uint32_t index, const OH_NN_Tensor& nnTensor) const; private: struct ExeTensor { diff --git a/frameworks/native/hdi_device.cpp b/frameworks/native/hdi_device_v1_0.cpp similarity index 68% rename from frameworks/native/hdi_device.cpp rename to frameworks/native/hdi_device_v1_0.cpp index b360ea73145b6c41fcb3324d0b3812a5ef155e4c..c87c51ab65f4a22110403cbd39dbbc4f83fb6f21 100644 --- a/frameworks/native/hdi_device.cpp +++ b/frameworks/native/hdi_device_v1_0.cpp @@ -13,12 +13,12 @@ * limitations under the License. */ -#include "hdi_device.h" +#include "hdi_device_v1_0.h" #include "hdf_base.h" #include "mindir.h" -#include "hdi_prepared_model.h" +#include "hdi_prepared_model_v1_0.h" #include "memory_manager.h" #include "transform.h" #include "common/log.h" @@ -26,12 +26,72 @@ namespace OHOS { namespace NeuralNetworkRuntime { -HDIDevice::HDIDevice(OHOS::sptr device) : m_iDevice(device) +namespace { +OH_NN_DeviceType TransHDIDeviceV1_0Type(const V1_0::DeviceType& iDeviceType) +{ + switch (iDeviceType) { + case V1_0::DeviceType::CPU: + return OH_NN_CPU; + case V1_0::DeviceType::GPU: + return OH_NN_GPU; + case V1_0::DeviceType::ACCELERATOR: + return OH_NN_ACCELERATOR; + default: + return OH_NN_OTHERS; + } +} + +DeviceStatus TransHDIDeviceV1_0Status(const V1_0::DeviceStatus& iDeviceStatus) +{ + switch (iDeviceStatus) { + case V1_0::DeviceStatus::AVAILABLE: + return DeviceStatus::AVAILABLE; + case V1_0::DeviceStatus::BUSY: + return DeviceStatus::BUSY; + case V1_0::DeviceStatus::OFFLINE: + return DeviceStatus::OFFLINE; + default: + return DeviceStatus::UNKNOWN; + } +} + +V1_0::PerformanceMode TransPerformanceMode(const OH_NN_PerformanceMode& mode) +{ + switch (mode) { + case OH_NN_PERFORMANCE_LOW: + return V1_0::PerformanceMode::PERFORMANCE_LOW; + case OH_NN_PERFORMANCE_MEDIUM: + return V1_0::PerformanceMode::PERFORMANCE_MEDIUM; + case OH_NN_PERFORMANCE_HIGH: + return V1_0::PerformanceMode::PERFORMANCE_HIGH; + case OH_NN_PERFORMANCE_EXTREME: + return V1_0::PerformanceMode::PERFORMANCE_EXTREME; + default: + return V1_0::PerformanceMode::PERFORMANCE_NONE; + } +} + +V1_0::Priority TransPriority(const OH_NN_Priority& priority) +{ + switch (priority) { + case OH_NN_PRIORITY_LOW: + return V1_0::Priority::PRIORITY_LOW; + case OH_NN_PRIORITY_MEDIUM: + return V1_0::Priority::PRIORITY_MEDIUM; + case OH_NN_PRIORITY_HIGH: + return V1_0::Priority::PRIORITY_HIGH; + default: + return V1_0::Priority::PRIORITY_NONE; + } +} +} + +HDIDeviceV1_0::HDIDeviceV1_0(OHOS::sptr device) : m_iDevice(device) { device->GetVersion(m_hdiVersion.first, m_hdiVersion.second); } -OH_NN_ReturnCode HDIDevice::GetDeviceName(std::string& name) +OH_NN_ReturnCode HDIDeviceV1_0::GetDeviceName(std::string& name) { auto ret = m_iDevice->GetDeviceName(name); if (ret != HDF_SUCCESS) { @@ -41,7 +101,7 @@ OH_NN_ReturnCode HDIDevice::GetDeviceName(std::string& name) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::GetVendorName(std::string& name) +OH_NN_ReturnCode HDIDeviceV1_0::GetVendorName(std::string& name) { auto ret = m_iDevice->GetVendorName(name); if (ret != HDF_SUCCESS) { @@ -51,7 +111,13 @@ OH_NN_ReturnCode HDIDevice::GetVendorName(std::string& name) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::GetDeviceType(OH_NN_DeviceType& deviceType) +OH_NN_ReturnCode HDIDeviceV1_0::GetVersion(std::string& version) +{ + version = 'v' + std::to_string(m_hdiVersion.first) + '_' + std::to_string(m_hdiVersion.second); + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV1_0::GetDeviceType(OH_NN_DeviceType& deviceType) { V1_0::DeviceType iDeviceType; auto ret = m_iDevice->GetDeviceType(iDeviceType); @@ -60,11 +126,11 @@ OH_NN_ReturnCode HDIDevice::GetDeviceType(OH_NN_DeviceType& deviceType) return OH_NN_UNAVALIDABLE_DEVICE; } - deviceType = HDIToNN::TransHDIDeviceType(iDeviceType); + deviceType = TransHDIDeviceV1_0Type(iDeviceType); return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::GetDeviceStatus(DeviceStatus& status) +OH_NN_ReturnCode HDIDeviceV1_0::GetDeviceStatus(DeviceStatus& status) { V1_0::DeviceStatus iDeviceStatus; auto ret = m_iDevice->GetDeviceStatus(iDeviceStatus); @@ -72,11 +138,11 @@ OH_NN_ReturnCode HDIDevice::GetDeviceStatus(DeviceStatus& status) LOGE("Get HDI device status failed. ErrorCode=%d", ret); return OH_NN_UNAVALIDABLE_DEVICE; } - status = HDIToNN::TransHDIDeviceStatus(iDeviceStatus); + status = TransHDIDeviceV1_0Status(iDeviceStatus); return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::GetSupportedOperation(std::shared_ptr model, +OH_NN_ReturnCode HDIDeviceV1_0::GetSupportedOperation(std::shared_ptr model, std::vector& ops) { if (model == nullptr) { @@ -84,7 +150,7 @@ OH_NN_ReturnCode HDIDevice::GetSupportedOperation(std::shared_ptr 0) { @@ -117,7 +183,7 @@ OH_NN_ReturnCode HDIDevice::GetSupportedOperation(std::shared_ptrIsFloat16PrecisionSupported(isSupported); if (ret != HDF_SUCCESS) { @@ -127,7 +193,7 @@ OH_NN_ReturnCode HDIDevice::IsFloat16PrecisionSupported(bool& isSupported) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::IsPerformanceModeSupported(bool& isSupported) +OH_NN_ReturnCode HDIDeviceV1_0::IsPerformanceModeSupported(bool& isSupported) { auto ret = m_iDevice->IsPerformanceModeSupported(isSupported); if (ret != HDF_SUCCESS) { @@ -137,7 +203,7 @@ OH_NN_ReturnCode HDIDevice::IsPerformanceModeSupported(bool& isSupported) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::IsPrioritySupported(bool& isSupported) +OH_NN_ReturnCode HDIDeviceV1_0::IsPrioritySupported(bool& isSupported) { auto ret = m_iDevice->IsPrioritySupported(isSupported); if (ret != HDF_SUCCESS) { @@ -147,7 +213,7 @@ OH_NN_ReturnCode HDIDevice::IsPrioritySupported(bool& isSupported) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::IsDynamicInputSupported(bool& isSupported) +OH_NN_ReturnCode HDIDeviceV1_0::IsDynamicInputSupported(bool& isSupported) { auto ret = m_iDevice->IsDynamicInputSupported(isSupported); if (ret != HDF_SUCCESS) { @@ -157,7 +223,7 @@ OH_NN_ReturnCode HDIDevice::IsDynamicInputSupported(bool& isSupported) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::IsModelCacheSupported(bool& isSupported) +OH_NN_ReturnCode HDIDeviceV1_0::IsModelCacheSupported(bool& isSupported) { auto ret = m_iDevice->IsModelCacheSupported(isSupported); if (ret != HDF_SUCCESS) { @@ -167,7 +233,7 @@ OH_NN_ReturnCode HDIDevice::IsModelCacheSupported(bool& isSupported) return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIDevice::PrepareModel(std::shared_ptr model, +OH_NN_ReturnCode HDIDeviceV1_0::PrepareModel(std::shared_ptr model, const ModelConfig& config, std::shared_ptr& preparedModel) { @@ -176,7 +242,7 @@ OH_NN_ReturnCode HDIDevice::PrepareModel(std::shared_ptr 0) { @@ -196,8 +262,8 @@ OH_NN_ReturnCode HDIDevice::PrepareModel(std::shared_ptr iPreparedModel; auto preparedRet = m_iDevice->PrepareModel(*iModel, iModelConfig, iPreparedModel); @@ -213,7 +279,7 @@ OH_NN_ReturnCode HDIDevice::PrepareModel(std::shared_ptr(iPreparedModel); + preparedModel = CreateSharedPtr(iPreparedModel); if (preparedModel == nullptr) { LOGE("Prepare model failed, because fail to create preparedModel instance."); return OH_NN_MEMORY_ERROR; @@ -222,7 +288,7 @@ OH_NN_ReturnCode HDIDevice::PrepareModel(std::shared_ptr& modelCache, +OH_NN_ReturnCode HDIDeviceV1_0::PrepareModelFromModelCache(const std::vector& modelCache, const ModelConfig& config, std::shared_ptr& preparedModel) { @@ -242,8 +308,8 @@ OH_NN_ReturnCode HDIDevice::PrepareModelFromModelCache(const std::vector iPreparedModel; auto hdiRet = m_iDevice->PrepareModelFromModelCache(iBuffers, iModelConfig, iPreparedModel); @@ -252,7 +318,7 @@ OH_NN_ReturnCode HDIDevice::PrepareModelFromModelCache(const std::vector(iPreparedModel); + preparedModel = CreateSharedPtr(iPreparedModel); if (preparedModel == nullptr) { LOGE("Prepare model from model cache failed, because fail to create preparedModel instance."); return OH_NN_MEMORY_ERROR; @@ -260,7 +326,7 @@ OH_NN_ReturnCode HDIDevice::PrepareModelFromModelCache(const std::vector model, + const ModelConfig& config, + std::shared_ptr& preparedModel) +{ + LOGE("HDIDeviceV1.0 not support PrepareOfflineModel."); + return OH_NN_OPERATION_FORBIDDEN; +} } // namespace NeuralNetworkRuntime -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/frameworks/native/hdi_device.h b/frameworks/native/hdi_device_v1_0.h similarity index 77% rename from frameworks/native/hdi_device.h rename to frameworks/native/hdi_device_v1_0.h index d795832e4ff5456b3fa1cb050831d35a713ae121..9b5647c9e21579b2e1e42a7811e423c1db01ac17 100644 --- a/frameworks/native/hdi_device.h +++ b/frameworks/native/hdi_device_v1_0.h @@ -13,22 +13,28 @@ * limitations under the License. */ -#ifndef NEURAL_NETWORK_RUNTIME_HDI_DEVICE_H -#define NEURAL_NETWORK_RUNTIME_HDI_DEVICE_H +#ifndef NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V1_0_H +#define NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V1_0_H #include "refbase.h" -#include "hdi_interfaces.h" +#include +#include +#include #include "device.h" namespace OHOS { namespace NeuralNetworkRuntime { -class HDIDevice : public Device { + +namespace V1_0 = OHOS::HDI::Nnrt::V1_0; + +class HDIDeviceV1_0 : public Device { public: - explicit HDIDevice(OHOS::sptr device); + explicit HDIDeviceV1_0(OHOS::sptr device); OH_NN_ReturnCode GetDeviceName(std::string& name) override; OH_NN_ReturnCode GetVendorName(std::string& name) override; + OH_NN_ReturnCode GetVersion(std::string& version) override; OH_NN_ReturnCode GetDeviceType(OH_NN_DeviceType& deviceType) override; OH_NN_ReturnCode GetDeviceStatus(DeviceStatus& status) override; OH_NN_ReturnCode GetSupportedOperation(std::shared_ptr model, @@ -46,6 +52,9 @@ public: OH_NN_ReturnCode PrepareModelFromModelCache(const std::vector& modelCache, const ModelConfig& config, std::shared_ptr& preparedModel) override; + OH_NN_ReturnCode PrepareOfflineModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) override; void* AllocateBuffer(size_t length) override; OH_NN_ReturnCode ReleaseBuffer(const void* buffer) override; @@ -60,4 +69,4 @@ private: }; } // namespace NeuralNetworkRuntime } // namespace OHOS -#endif // NEURAL_NETWORK_RUNTIME_HDI_DEVICE_H \ No newline at end of file +#endif // NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V1_0_H \ No newline at end of file diff --git a/frameworks/native/hdi_device_v2_0.cpp b/frameworks/native/hdi_device_v2_0.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68c1fe561e95a63c84d73dd012ea9e711af78967 --- /dev/null +++ b/frameworks/native/hdi_device_v2_0.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "hdi_device_v2_0.h" + +#include "hdf_base.h" +#include "mindir.h" +#include "securec.h" + +#include "hdi_prepared_model_v2_0.h" +#include "hdi_returncode_transform.h" +#include "memory_manager.h" +#include "transform.h" +#include "common/log.h" +#include "common/utils.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { +namespace { +OH_NN_DeviceType TransHDIDeviceV2_0Type(const V2_0::DeviceType& iDeviceType) +{ + switch (iDeviceType) { + case V2_0::DeviceType::CPU: + return OH_NN_CPU; + case V2_0::DeviceType::GPU: + return OH_NN_GPU; + case V2_0::DeviceType::ACCELERATOR: + return OH_NN_ACCELERATOR; + default: + return OH_NN_OTHERS; + } +} + +DeviceStatus TransHDIDeviceV2_0Status(const V2_0::DeviceStatus& iDeviceStatus) +{ + switch (iDeviceStatus) { + case V2_0::DeviceStatus::AVAILABLE: + return DeviceStatus::AVAILABLE; + case V2_0::DeviceStatus::BUSY: + return DeviceStatus::BUSY; + case V2_0::DeviceStatus::OFFLINE: + return DeviceStatus::OFFLINE; + default: + return DeviceStatus::UNKNOWN; + } +} + +V2_0::PerformanceMode TransPerformanceMode(const OH_NN_PerformanceMode& mode) +{ + switch (mode) { + case OH_NN_PERFORMANCE_LOW: + return V2_0::PerformanceMode::PERFORMANCE_LOW; + case OH_NN_PERFORMANCE_MEDIUM: + return V2_0::PerformanceMode::PERFORMANCE_MEDIUM; + case OH_NN_PERFORMANCE_HIGH: + return V2_0::PerformanceMode::PERFORMANCE_HIGH; + case OH_NN_PERFORMANCE_EXTREME: + return V2_0::PerformanceMode::PERFORMANCE_EXTREME; + default: + return V2_0::PerformanceMode::PERFORMANCE_NONE; + } +} + +V2_0::Priority TransPriority(const OH_NN_Priority& priority) +{ + switch (priority) { + case OH_NN_PRIORITY_LOW: + return V2_0::Priority::PRIORITY_LOW; + case OH_NN_PRIORITY_MEDIUM: + return V2_0::Priority::PRIORITY_MEDIUM; + case OH_NN_PRIORITY_HIGH: + return V2_0::Priority::PRIORITY_HIGH; + default: + return V2_0::Priority::PRIORITY_NONE; + } +} +} + +HDIDeviceV2_0::HDIDeviceV2_0(OHOS::sptr device) : m_iDevice(device) +{ + device->GetVersion(m_hdiVersion.first, m_hdiVersion.second); +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceName(std::string& name) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->GetDeviceName(name, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Get HDI device name failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetVendorName(std::string& name) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->GetVendorName(name, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Get HDI device vendor name failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetVersion(std::string& version) +{ + version = 'v' + std::to_string(m_hdiVersion.first) + '_' + std::to_string(m_hdiVersion.second); + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceType(OH_NN_DeviceType& deviceType) +{ + V2_0::DeviceType iDeviceType; + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->GetDeviceType(iDeviceType, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Get HDI device type failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + + deviceType = TransHDIDeviceV2_0Type(iDeviceType); + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceStatus(DeviceStatus& status) +{ + V2_0::DeviceStatus iDeviceStatus; + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->GetDeviceStatus(iDeviceStatus, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Get HDI device status failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + status = TransHDIDeviceV2_0Status(iDeviceStatus); + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetSupportedOperation(std::shared_ptr model, + std::vector& ops) +{ + if (model == nullptr) { + LOGE("Model is nullptr, cannot query supported operation."); + return OH_NN_NULL_PTR; + } + + OHOS::HDI::Nnrt::V2_0::SharedBuffer tensorBuffer {INVALID_FD, 0, 0, 0}; + size_t tensorSize = mindspore::lite::MindIR_LiteGraph_GetConstTensorSize(model.get()); + int32_t hdiRet {0}; + if (tensorSize > 0) { + V2_0::NNRT_ReturnCode returnCode; + hdiRet = m_iDevice->AllocateBuffer(tensorSize, tensorBuffer, returnCode); + if (hdiRet != HDF_SUCCESS || tensorBuffer.fd == INVALID_FD) { + LOGE("Allocate tensor buffer error when get supported operation. ErrorCode: %{public}d, \ + innerHDIRet=%{public}s", hdiRet, ConverterRetToString(returnCode).c_str()); + return OH_NN_FAILED; + } + } + + auto iModel = mindspore::lite::MindIR_LiteGraph_To_Model(model.get(), tensorBuffer); + if (iModel == nullptr) { + LOGE("Parse litegraph to hdi model failed."); + ReleaseSharedBuffer(tensorBuffer); + return OH_NN_FAILED; + } + + V2_0::NNRT_ReturnCode returnCode; + hdiRet = m_iDevice->GetSupportedOperation(*iModel, ops, returnCode); + + mindspore::lite::MindIR_Model_Destroy(&iModel); + auto ret = ReleaseSharedBuffer(tensorBuffer); + if (ret != OH_NN_SUCCESS) { + LOGE("Release tensorBuffer failed."); + return OH_NN_FAILED; + } + if (hdiRet != HDF_SUCCESS) { + LOGE("Get supported operation failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + hdiRet, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::IsFloat16PrecisionSupported(bool& isSupported) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->IsFloat16PrecisionSupported(isSupported, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Query fp16 precision supported failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::IsPerformanceModeSupported(bool& isSupported) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->IsPerformanceModeSupported(isSupported, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Query performance mode supported failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::IsPrioritySupported(bool& isSupported) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->IsPrioritySupported(isSupported, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Query priority supported failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::IsDynamicInputSupported(bool& isSupported) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->IsDynamicInputSupported(isSupported, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Query dynamic input supported failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::IsModelCacheSupported(bool& isSupported) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->IsModelCacheSupported(isSupported, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Query cache model supported failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::PrepareModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) +{ + if (model == nullptr) { + LOGE("Model is nullptr, cannot prepare model."); + return OH_NN_INVALID_PARAMETER; + } + + OHOS::HDI::Nnrt::V2_0::SharedBuffer tensorBuffer {INVALID_FD, 0, 0, 0}; + size_t tensorSize = mindspore::lite::MindIR_LiteGraph_GetConstTensorSize(model.get()); + int32_t hdiRet {0}; + if (tensorSize > 0) { + V2_0::NNRT_ReturnCode returnCode; + hdiRet = m_iDevice->AllocateBuffer(tensorSize, tensorBuffer, returnCode); + if (hdiRet != HDF_SUCCESS || tensorBuffer.fd == INVALID_FD) { + LOGE("Allocate tensor buffer error when prepare model. ErrorCode: %{public}d, innerHDIRet=%{public}s", + hdiRet, ConverterRetToString(returnCode).c_str()); + return OH_NN_FAILED; + } + } + + V2_0::Model* iModel = mindspore::lite::MindIR_LiteGraph_To_Model(model.get(), tensorBuffer); + if (iModel == nullptr) { + LOGE("Parse litegraph to hdi model failed."); + ReleaseSharedBuffer(tensorBuffer); + return OH_NN_FAILED; + } + + V2_0::ModelConfig iModelConfig; + iModelConfig.enableFloat16 = config.enableFloat16; + iModelConfig.mode = TransPerformanceMode(config.mode); + iModelConfig.priority = TransPriority(config.priority); + OHOS::sptr iPreparedModel; + + V2_0::NNRT_ReturnCode returnCode; + auto preparedRet = m_iDevice->PrepareModel(*iModel, iModelConfig, iPreparedModel, returnCode); + + mindspore::lite::MindIR_Model_Destroy(&iModel); + auto ret = ReleaseSharedBuffer(tensorBuffer); + if (ret != OH_NN_SUCCESS) { + LOGE("Release tensorBuffer failed."); + return OH_NN_FAILED; + } + if (preparedRet != HDF_SUCCESS || iPreparedModel == nullptr) { + LOGE("Prepare model failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + preparedRet, ConverterRetToString(returnCode).c_str()); + return OH_NN_FAILED; + } + + preparedModel = CreateSharedPtr(iPreparedModel); + if (preparedModel == nullptr) { + LOGE("Prepare model failed, because fail to create preparedModel instance."); + return OH_NN_MEMORY_ERROR; + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::PrepareModelFromModelCache(const std::vector& modelCache, + const ModelConfig& config, + std::shared_ptr& preparedModel) +{ + std::vector iBuffers; + auto memManager = MemoryManager::GetInstance(); + Memory memory; + OH_NN_ReturnCode ret; + size_t modelCacheSize = modelCache.size(); + for (size_t i = 0; i < modelCacheSize; i++) { + ret = memManager->GetMemory(modelCache[i].buffer, memory); + if (ret != OH_NN_SUCCESS) { + LOGE("The %{public}zuth model cache is invalid. Please put valid model cache.", i + 1); + return ret; + } + iBuffers.emplace_back(V2_0::SharedBuffer {memory.fd, memory.length, 0, memory.length}); + } + + V2_0::ModelConfig iModelConfig; + iModelConfig.enableFloat16 = config.enableFloat16; + iModelConfig.mode = TransPerformanceMode(config.mode); + iModelConfig.priority = TransPriority(config.priority); + + OHOS::sptr iPreparedModel; + V2_0::NNRT_ReturnCode returnCode; + auto hdiRet = m_iDevice->PrepareModelFromModelCache(iBuffers, iModelConfig, iPreparedModel, returnCode); + if (hdiRet != HDF_SUCCESS) { + LOGE("Prepare model from cache failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + hdiRet, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + + preparedModel = CreateSharedPtr(iPreparedModel); + if (preparedModel == nullptr) { + LOGE("Prepare model from model cache failed, because fail to create preparedModel instance."); + return OH_NN_MEMORY_ERROR; + } + return OH_NN_SUCCESS; +} + +void* HDIDeviceV2_0::AllocateBuffer(size_t length) +{ + if (length == 0) { + LOGE("The length param is invalid, length=0"); + return nullptr; + } + + V2_0::SharedBuffer buffer; + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->AllocateBuffer(length, buffer, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Allocate buffer error. ErrorCode: %{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return nullptr; + } + + auto memManager = MemoryManager::GetInstance(); + auto addr = memManager->MapMemory(buffer.fd, length); + if (addr == nullptr) { + LOGE("Map fd to address failed."); + } + return addr; +} + +OH_NN_ReturnCode HDIDeviceV2_0::ReleaseBuffer(const void* buffer) +{ + if (buffer == nullptr) { + LOGE("Buffer is nullptr, no need to release."); + return OH_NN_INVALID_PARAMETER; + } + + auto memManager = MemoryManager::GetInstance(); + Memory memory; + auto ret = memManager->GetMemory(buffer, memory); + if (ret != OH_NN_SUCCESS) { + LOGE("Invalid Buffer, it is not NNRt buffer."); + return ret; + } + + V2_0::SharedBuffer hdiBuffer {memory.fd, memory.length, 0, memory.length}; + V2_0::NNRT_ReturnCode returnCode; + auto deviceResult = m_iDevice->ReleaseBuffer(hdiBuffer, returnCode); + if (deviceResult != HDF_SUCCESS) { + LOGE("Device release buffer error. ErrorCode: %{public}d, innerHDIRet=%{public}s", + deviceResult, ConverterRetToString(returnCode).c_str()); + return OH_NN_FAILED; + } + + ret = memManager->UnMapMemory(buffer); + if (ret != OH_NN_SUCCESS) { + LOGE("Unmap memory failed."); + return ret; + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::ReleaseSharedBuffer(const V2_0::SharedBuffer& buffer) +{ + if (buffer.fd == INVALID_FD) { + LOGI("No need to release. fd=%{public}d", INVALID_FD); + return OH_NN_SUCCESS; + } + + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_iDevice->ReleaseBuffer(buffer, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("Device release buffer error. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_FAILED; + } + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::GetOfflineModelFromLiteGraph(std::shared_ptr graph, + std::vector>& offlineModels) +{ + // graph has been checked in PrepareOfflineModel, no need to check twice. + offlineModels.clear(); + + const size_t inputNum = graph->input_indices_.size(); + if (inputNum < (size_t)2) { + LOGE("LiteGraph with offline model should have at least two input tensors, only get %zu.", inputNum); + return OH_NN_INVALID_PARAMETER; + } + + // The offline model is integrated into input tensors with index larger than 0. + mindspore::lite::TensorPtr pTensor; + std::vector offlineModel; + for (size_t i = 1; i < inputNum; i++) { + pTensor = graph->all_tensors_[i]; + offlineModel = mindspore::lite::MindIR_Tensor_GetData(pTensor); + if (offlineModel.size() == (size_t)0) { + LOGE("Offline model has size of 0, please check the ms model."); + return OH_NN_INVALID_PARAMETER; + } + + offlineModels.emplace_back(std::move(offlineModel)); + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::AllocateDeviceBufferForOfflineModel( + const std::vector>& offlineModels, std::vector& deviceBuffers) +{ + // offlineModels is guaranteed to have at least one element in GetOfflineModelFromLiteGraph, no need to check size. + deviceBuffers.clear(); + + for (const std::vector& offlineModel : offlineModels) { + const size_t offlineModelSize = offlineModel.size(); + + void* newModelBuffer = AllocateBuffer(offlineModelSize); + if (newModelBuffer == nullptr) { + // Release allocated model buffer if error happens. + OH_NN_ReturnCode status {OH_NN_SUCCESS}; + for (const ModelBuffer& deviceBuffer : deviceBuffers) { + status = ReleaseBuffer(deviceBuffer.buffer); + if (status != OH_NN_SUCCESS) { + LOGE("Release shared buffer of offline model failed."); + return status; + } + } + + deviceBuffers.clear(); + LOGE("Error happens when allocating shared buffer for offline model."); + return OH_NN_MEMORY_ERROR; + } + + ModelBuffer modelBuffer {nullptr, 0}; + modelBuffer.buffer = newModelBuffer; + modelBuffer.length = offlineModelSize; + deviceBuffers.emplace_back(modelBuffer); + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::CopyOfflineModelToDevice(const std::vector>& offlineModels, + std::vector& deviceBuffers) +{ + if (offlineModels.size() != deviceBuffers.size()) { + LOGE("CopyOfflineModelToDevice failed, number of offlineModels not equal to allocated buffers."); + return OH_NN_INVALID_PARAMETER; + } + + const void* offlineModel {nullptr}; + size_t offlineModelSize {0}; + void* deviceBuffer {nullptr}; + size_t deviceBufferSize {0}; + + for (size_t i = 0; i < offlineModels.size(); i++) { + offlineModel = offlineModels[i].data(); + offlineModelSize = offlineModels[i].size(); + deviceBuffer = deviceBuffers[i].buffer; + deviceBufferSize = deviceBuffers[i].length; + + // Copy offline model to shared buffer of device. + errno_t errorCode = memcpy_s(deviceBuffer, deviceBufferSize, offlineModel, offlineModelSize); + if (errorCode != EOK) { + LOGE("Error happened when copy offline model to device buffer. Error code: %d.", errorCode); + return OH_NN_MEMORY_ERROR; + } + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::PrepareOfflineModel(std::vector& deviceBuffers, + const ModelConfig& config, + std::shared_ptr& preparedModel) +{ + V2_0::ModelConfig iModelConfig; + iModelConfig.enableFloat16 = config.enableFloat16; + iModelConfig.mode = TransPerformanceMode(config.mode); + iModelConfig.priority = TransPriority(config.priority); + OHOS::sptr iPreparedModel; + + std::vector iBuffers; + auto memManager = MemoryManager::GetInstance(); + Memory memory; + OH_NN_ReturnCode ret; + size_t numOfflineModel = deviceBuffers.size(); + for (size_t i = 0; i < numOfflineModel; i++) { + ret = memManager->GetMemory(deviceBuffers[i].buffer, memory); + if (ret != OH_NN_SUCCESS) { + LOGE("Retrieve the memory of %zuth device buffer failed.", i); + return ret; + } + iBuffers.emplace_back(V2_0::SharedBuffer {memory.fd, memory.length, 0, memory.length}); + } + + V2_0::NNRT_ReturnCode HDIReturnCode {V2_0::NNRT_ReturnCode::NNRT_SUCCESS}; + auto preparedRet = m_iDevice->PrepareOfflineModel(iBuffers, iModelConfig, iPreparedModel, HDIReturnCode); + + // Release allocated model buffer after prepare model. + OH_NN_ReturnCode status {OH_NN_SUCCESS}; + for (const ModelBuffer& deviceBuffer : deviceBuffers) { + status = ReleaseBuffer(deviceBuffer.buffer); + if (status != OH_NN_SUCCESS) { + LOGE("Release shared buffer of offline model failed."); + return status; + } + } + deviceBuffers.clear(); + + if (preparedRet != HDF_SUCCESS || iPreparedModel == nullptr) { + LOGE("Prepare model failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + preparedRet, ConverterRetToString(HDIReturnCode).c_str()); + return OH_NN_FAILED; + } + + preparedModel = CreateSharedPtr(iPreparedModel); + if (preparedModel == nullptr) { + LOGE("Prepare model failed, because fail to create preparedModel instance."); + return OH_NN_MEMORY_ERROR; + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIDeviceV2_0::PrepareOfflineModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) +{ + if (model == nullptr) { + LOGE("LiteGraph is empty when identifying the offline model."); + return OH_NN_NULL_PTR; + } + + std::vector> offlineModels; + OH_NN_ReturnCode status = GetOfflineModelFromLiteGraph(model, offlineModels); + if (status != OH_NN_SUCCESS) { + LOGE("Error happens when getting offline models from lite graph."); + return status; + } + + std::vector deviceBuffers; + status = AllocateDeviceBufferForOfflineModel(offlineModels, deviceBuffers); + if (status != OH_NN_SUCCESS) { + LOGE("Error happens when allocating device buffers for offline model."); + return status; + } + + status = CopyOfflineModelToDevice(offlineModels, deviceBuffers); + if (status != OH_NN_SUCCESS) { + LOGE("Error happened when copying offline models to device buffers."); + + OH_NN_ReturnCode ret {OH_NN_SUCCESS}; + // Release allocated model buffer if error happens. + for (const ModelBuffer& deviceBuffer : deviceBuffers) { + ret = ReleaseBuffer(deviceBuffer.buffer); + if (ret != OH_NN_SUCCESS) { + LOGE("Releasing device buffer failed after copying offline models to device buffers failed."); + return ret; + } + } + + return status; + } + + status = PrepareOfflineModel(deviceBuffers, config, preparedModel); + if (status != OH_NN_SUCCESS) { + LOGE("PrepareOfflineModel failed."); + return status; + } + + return OH_NN_SUCCESS; +} +} // namespace NeuralNetworkRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/hdi_device_v2_0.h b/frameworks/native/hdi_device_v2_0.h new file mode 100644 index 0000000000000000000000000000000000000000..f8cba175df799eec9ff4675632046c7bc158c2ee --- /dev/null +++ b/frameworks/native/hdi_device_v2_0.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V2_0_H +#define NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V2_0_H + +#include "refbase.h" +#include +#include +#include + +#include "device.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { + +namespace V2_0 = OHOS::HDI::Nnrt::V2_0; + +class HDIDeviceV2_0 : public Device { +public: + explicit HDIDeviceV2_0(OHOS::sptr device); + + OH_NN_ReturnCode GetDeviceName(std::string& name) override; + OH_NN_ReturnCode GetVendorName(std::string& name) override; + OH_NN_ReturnCode GetVersion(std::string& version) override; + OH_NN_ReturnCode GetDeviceType(OH_NN_DeviceType& deviceType) override; + OH_NN_ReturnCode GetDeviceStatus(DeviceStatus& status) override; + OH_NN_ReturnCode GetSupportedOperation(std::shared_ptr model, + std::vector& ops) override; + + OH_NN_ReturnCode IsFloat16PrecisionSupported(bool& isSupported) override; + OH_NN_ReturnCode IsPerformanceModeSupported(bool& isSupported) override; + OH_NN_ReturnCode IsPrioritySupported(bool& isSupported) override; + OH_NN_ReturnCode IsDynamicInputSupported(bool& isSupported) override; + OH_NN_ReturnCode IsModelCacheSupported(bool& isSupported) override; + + OH_NN_ReturnCode PrepareModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) override; + OH_NN_ReturnCode PrepareModelFromModelCache(const std::vector& modelCache, + const ModelConfig& config, + std::shared_ptr& preparedModel) override; + OH_NN_ReturnCode PrepareOfflineModel(std::shared_ptr model, + const ModelConfig& config, + std::shared_ptr& preparedModel) override; + + void* AllocateBuffer(size_t length) override; + OH_NN_ReturnCode ReleaseBuffer(const void* buffer) override; + +private: + OH_NN_ReturnCode ReleaseSharedBuffer(const V2_0::SharedBuffer& buffer); + OH_NN_ReturnCode GetOfflineModelFromLiteGraph(std::shared_ptr graph, + std::vector>& offlineModels); + OH_NN_ReturnCode AllocateDeviceBufferForOfflineModel(const std::vector>& offlineModels, + std::vector& deviceBuffers); + OH_NN_ReturnCode CopyOfflineModelToDevice(const std::vector>& offlineModels, + std::vector& deviceBuffers); + OH_NN_ReturnCode PrepareOfflineModel(std::vector& deviceBuffers, + const ModelConfig& config, + std::shared_ptr& preparedModel); + +private: + // first: major version, second: minor version + std::pair m_hdiVersion; + OHOS::sptr m_iDevice {nullptr}; +}; +} // namespace NeuralNetworkRuntime +} // namespace OHOS +#endif // NEURAL_NETWORK_RUNTIME_HDI_DEVICE_V2_0_H \ No newline at end of file diff --git a/frameworks/native/hdi_prepared_model.cpp b/frameworks/native/hdi_prepared_model_v1_0.cpp similarity index 51% rename from frameworks/native/hdi_prepared_model.cpp rename to frameworks/native/hdi_prepared_model_v1_0.cpp index 491aec696489b34b44c32bad5cdd5a8c93d7c969..898d37990ad63e39538b9206b0f10283cccb6680 100644 --- a/frameworks/native/hdi_prepared_model.cpp +++ b/frameworks/native/hdi_prepared_model_v1_0.cpp @@ -13,21 +13,93 @@ * limitations under the License. */ -#include "hdi_prepared_model.h" +#include "hdi_prepared_model_v1_0.h" #include "common/log.h" #include "memory_manager.h" -#include "transform.h" namespace OHOS { namespace NeuralNetworkRuntime { -HDIPreparedModel::HDIPreparedModel(OHOS::sptr hdiPreparedModel) +namespace { +V1_0::DataType TransDataType(const OH_NN_DataType& dataType) +{ + switch (dataType) { + case OH_NN_BOOL: + return V1_0::DataType::DATA_TYPE_BOOL; + case OH_NN_INT8: + return V1_0::DataType::DATA_TYPE_INT8; + case OH_NN_INT16: + return V1_0::DataType::DATA_TYPE_INT16; + case OH_NN_INT32: + return V1_0::DataType::DATA_TYPE_INT32; + case OH_NN_INT64: + return V1_0::DataType::DATA_TYPE_INT64; + case OH_NN_UINT8: + return V1_0::DataType::DATA_TYPE_UINT8; + case OH_NN_UINT16: + return V1_0::DataType::DATA_TYPE_UINT16; + case OH_NN_UINT32: + return V1_0::DataType::DATA_TYPE_UINT32; + case OH_NN_UINT64: + return V1_0::DataType::DATA_TYPE_UINT64; + case OH_NN_FLOAT16: + return V1_0::DataType::DATA_TYPE_FLOAT16; + case OH_NN_FLOAT32: + return V1_0::DataType::DATA_TYPE_FLOAT32; + case OH_NN_FLOAT64: + return V1_0::DataType::DATA_TYPE_FLOAT64; + default: + return V1_0::DataType::DATA_TYPE_UNKNOWN; + } +} + +V1_0::Format TransFormat(const OH_NN_Format& format) +{ + switch (format) { + case OH_NN_FORMAT_NCHW: + return V1_0::Format::FORMAT_NCHW; + case OH_NN_FORMAT_NHWC: + return V1_0::Format::FORMAT_NHWC; + default: + return V1_0::Format::FORMAT_NONE; + } +} + +V1_0::IOTensor TransIOTensor(const IOTensor& tensor) +{ + V1_0::IOTensor iTensor; + iTensor.name = tensor.name; + iTensor.dataType = TransDataType(tensor.dataType); + iTensor.dimensions = tensor.dimensions; + iTensor.format = TransFormat(tensor.format); + + V1_0::SharedBuffer iBuffer {INVALID_FD, 0, 0, 0}; + if (tensor.data != nullptr) { + auto memManager = MemoryManager::GetInstance(); + Memory memory; + auto ret = memManager->GetMemory(tensor.data, memory); + if (ret != OH_NN_SUCCESS) { + LOGE("Invalid Tensor buffer, cannot transform to fd."); + } else { + iBuffer.fd = memory.fd; + iBuffer.bufferSize = memory.length; + iBuffer.offset = 0; + iBuffer.dataSize = memory.length; + } + } + iTensor.data = iBuffer; + + return iTensor; +} +} // unamed namespace + +HDIPreparedModelV1_0::HDIPreparedModelV1_0(OHOS::sptr hdiPreparedModel) : m_hdiPreparedModel(hdiPreparedModel) { hdiPreparedModel->GetVersion(m_hdiVersion.first, m_hdiVersion.second); } -OH_NN_ReturnCode HDIPreparedModel::ExportModelCache(std::vector& modelCache) +OH_NN_ReturnCode HDIPreparedModelV1_0::ExportModelCache(std::vector& modelCache) { if (!modelCache.empty()) { LOGE("The vector of modelCache should be empty. size=%zu", modelCache.size()); @@ -55,13 +127,13 @@ OH_NN_ReturnCode HDIPreparedModel::ExportModelCache(std::vector& mo return OH_NN_SUCCESS; } -OH_NN_ReturnCode HDIPreparedModel::Run(const std::vector& inputs, const std::vector& outputs, +OH_NN_ReturnCode HDIPreparedModelV1_0::Run(const std::vector& inputs, const std::vector& outputs, std::vector>& outputsDims, std::vector& isOutputBufferEnough) { V1_0::IOTensor iTensor; std::vector iInputTensors; for (auto& input: inputs) { - iTensor = NNToHDI::TransIOTensor(input); + iTensor = TransIOTensor(input); if (iTensor.data.fd == INVALID_FD) { LOGE("Transform inputs tensor failed, cannot find data file descriptor."); return OH_NN_INVALID_PARAMETER; @@ -71,7 +143,7 @@ OH_NN_ReturnCode HDIPreparedModel::Run(const std::vector& inputs, cons std::vector iOutputTensors; for (auto& output: outputs) { - iTensor = NNToHDI::TransIOTensor(output); + iTensor = TransIOTensor(output); if (iTensor.data.fd == INVALID_FD) { LOGE("Transform outputs tensor failed, cannot find data file descriptor."); return OH_NN_INVALID_PARAMETER; diff --git a/frameworks/native/hdi_prepared_model.h b/frameworks/native/hdi_prepared_model_v1_0.h similarity index 75% rename from frameworks/native/hdi_prepared_model.h rename to frameworks/native/hdi_prepared_model_v1_0.h index d111977b329e3377a95c0de03ae825b1121410cf..f5a8911095571fd46c4d14091181b85753ac45e5 100644 --- a/frameworks/native/hdi_prepared_model.h +++ b/frameworks/native/hdi_prepared_model_v1_0.h @@ -14,21 +14,25 @@ */ -#ifndef NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_H -#define NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_H +#ifndef NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V1_0_H +#define NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V1_0_H #include #include "refbase.h" -#include "hdi_interfaces.h" #include "prepared_model.h" #include "cpp_type.h" +#include +#include +#include + +namespace V1_0 = OHOS::HDI::Nnrt::V1_0; namespace OHOS { namespace NeuralNetworkRuntime { -class HDIPreparedModel : public PreparedModel { +class HDIPreparedModelV1_0 : public PreparedModel { public: - explicit HDIPreparedModel(OHOS::sptr hdiPreparedModel); + explicit HDIPreparedModelV1_0(OHOS::sptr hdiPreparedModel); OH_NN_ReturnCode ExportModelCache(std::vector& modelCache) override; @@ -44,4 +48,4 @@ private: }; } // namespace NeuralNetworkRuntime } // OHOS -#endif // NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_H \ No newline at end of file +#endif // NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V1_0_H \ No newline at end of file diff --git a/frameworks/native/hdi_prepared_model_v2_0.cpp b/frameworks/native/hdi_prepared_model_v2_0.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c07e7e7f4eedb50a53f00fe13a7cc07b2567749e --- /dev/null +++ b/frameworks/native/hdi_prepared_model_v2_0.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "hdi_prepared_model_v2_0.h" + +#include "common/log.h" +#include "hdi_returncode_transform.h" +#include "memory_manager.h" + +namespace OHOS { +namespace NeuralNetworkRuntime { +namespace { +V2_0::DataType TransDataType(const OH_NN_DataType& dataType) +{ + switch (dataType) { + case OH_NN_BOOL: + return V2_0::DataType::DATA_TYPE_BOOL; + case OH_NN_INT8: + return V2_0::DataType::DATA_TYPE_INT8; + case OH_NN_INT16: + return V2_0::DataType::DATA_TYPE_INT16; + case OH_NN_INT32: + return V2_0::DataType::DATA_TYPE_INT32; + case OH_NN_INT64: + return V2_0::DataType::DATA_TYPE_INT64; + case OH_NN_UINT8: + return V2_0::DataType::DATA_TYPE_UINT8; + case OH_NN_UINT16: + return V2_0::DataType::DATA_TYPE_UINT16; + case OH_NN_UINT32: + return V2_0::DataType::DATA_TYPE_UINT32; + case OH_NN_UINT64: + return V2_0::DataType::DATA_TYPE_UINT64; + case OH_NN_FLOAT16: + return V2_0::DataType::DATA_TYPE_FLOAT16; + case OH_NN_FLOAT32: + return V2_0::DataType::DATA_TYPE_FLOAT32; + case OH_NN_FLOAT64: + return V2_0::DataType::DATA_TYPE_FLOAT64; + default: + return V2_0::DataType::DATA_TYPE_UNKNOWN; + } +} + +V2_0::Format TransFormat(const OH_NN_Format& format) +{ + switch (format) { + case OH_NN_FORMAT_NCHW: + return V2_0::Format::FORMAT_NCHW; + case OH_NN_FORMAT_NHWC: + return V2_0::Format::FORMAT_NHWC; + default: + return V2_0::Format::FORMAT_NONE; + } +} + +V2_0::IOTensor TransIOTensor(const IOTensor& tensor) +{ + V2_0::IOTensor iTensor; + iTensor.name = tensor.name; + iTensor.dataType = TransDataType(tensor.dataType); + iTensor.dimensions = tensor.dimensions; + iTensor.format = TransFormat(tensor.format); + + V2_0::SharedBuffer iBuffer {INVALID_FD, 0, 0, 0}; + if (tensor.data != nullptr) { + auto memManager = MemoryManager::GetInstance(); + Memory memory; + auto ret = memManager->GetMemory(tensor.data, memory); + if (ret != OH_NN_SUCCESS) { + LOGE("Invalid Tensor buffer, cannot transform to fd."); + } else { + iBuffer.fd = memory.fd; + iBuffer.bufferSize = memory.length; + iBuffer.offset = 0; + iBuffer.dataSize = memory.length; + } + } + iTensor.data = iBuffer; + + return iTensor; +} +} // unamed namespace + +HDIPreparedModelV2_0::HDIPreparedModelV2_0(OHOS::sptr hdiPreparedModel) + : m_hdiPreparedModel(hdiPreparedModel) +{ + hdiPreparedModel->GetVersion(m_hdiVersion.first, m_hdiVersion.second); +} + +OH_NN_ReturnCode HDIPreparedModelV2_0::ExportModelCache(std::vector& modelCache) +{ + if (!modelCache.empty()) { + LOGE("The vector of modelCache should be empty. size=%{public}zu", modelCache.size()); + return OH_NN_INVALID_PARAMETER; + } + + std::vector iBuffers; + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_hdiPreparedModel->ExportModelCache(iBuffers, returnCode); + if (ret != HDF_SUCCESS || returnCode != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) { + LOGE("Export model cache failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + + auto memManager = MemoryManager::GetInstance(); + for (size_t i = 0; i < iBuffers.size(); i++) { + auto addr = memManager->MapMemory(iBuffers[i].fd, iBuffers[i].bufferSize); + if (addr == nullptr) { + LOGE("Export the %{public}zuth model cache failed, cannot not map fd to address.", i + 1); + return OH_NN_MEMORY_ERROR; + } + ModelBuffer modelbuffer {addr, iBuffers[i].bufferSize}; + modelCache.emplace_back(modelbuffer); + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIPreparedModelV2_0::Run(const std::vector& inputs, const std::vector& outputs, + std::vector>& outputsDims, std::vector& isOutputBufferEnough) +{ + V2_0::IOTensor iTensor; + std::vector iInputTensors; + for (auto& input: inputs) { + iTensor = TransIOTensor(input); + if (iTensor.data.fd == INVALID_FD) { + LOGE("Transform inputs tensor failed, cannot find data file descriptor."); + return OH_NN_INVALID_PARAMETER; + } + iInputTensors.emplace_back(iTensor); + } + + std::vector iOutputTensors; + for (auto& output: outputs) { + iTensor = TransIOTensor(output); + if (iTensor.data.fd == INVALID_FD) { + LOGE("Transform outputs tensor failed, cannot find data file descriptor."); + return OH_NN_INVALID_PARAMETER; + } + iOutputTensors.emplace_back(iTensor); + } + + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_hdiPreparedModel->Run(iInputTensors, iOutputTensors, outputsDims, returnCode); + if (ret != HDF_SUCCESS || outputsDims.empty()) { + LOGE("Run model failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + + return OH_NN_SUCCESS; +} + +OH_NN_ReturnCode HDIPreparedModelV2_0::GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims) +{ + V2_0::NNRT_ReturnCode returnCode; + auto ret = m_hdiPreparedModel->GetInputDimRanges(minInputDims, maxInputDims, returnCode); + if (ret != HDF_SUCCESS) { + LOGE("GetInputDimRanges failed. ErrorCode=%{public}d, innerHDIRet=%{public}s", + ret, ConverterRetToString(returnCode).c_str()); + return OH_NN_UNAVALIDABLE_DEVICE; + } + + return OH_NN_SUCCESS; +} +} // namespace NeuralNetworkRuntime +} // OHOS \ No newline at end of file diff --git a/frameworks/native/hdi_prepared_model_v2_0.h b/frameworks/native/hdi_prepared_model_v2_0.h new file mode 100644 index 0000000000000000000000000000000000000000..ad42dcbcb314c56727b8f641132fcddc23e2bb64 --- /dev/null +++ b/frameworks/native/hdi_prepared_model_v2_0.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V2_0_H +#define NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V2_0_H + +#include + +#include +#include +#include + +#include "refbase.h" +#include "prepared_model.h" +#include "cpp_type.h" + +namespace V2_0 = OHOS::HDI::Nnrt::V2_0; + +namespace OHOS { +namespace NeuralNetworkRuntime { +class HDIPreparedModelV2_0 : public PreparedModel { +public: + explicit HDIPreparedModelV2_0(OHOS::sptr hdiPreparedModel); + + OH_NN_ReturnCode ExportModelCache(std::vector& modelCache) override; + + OH_NN_ReturnCode Run(const std::vector& inputs, + const std::vector& outputs, + std::vector>& outputsDims, + std::vector& isOutputBufferEnough) override; + + OH_NN_ReturnCode GetInputDimRanges(std::vector>& minInputDims, + std::vector>& maxInputDims) override; + +private: + // first: major version, second: minor version + std::pair m_hdiVersion; + OHOS::sptr m_hdiPreparedModel {nullptr}; +}; +} // namespace NeuralNetworkRuntime +} // OHOS +#endif // NEURAL_NETWORK_RUNTIME_HDI_PREPARED_MODEL_V2_0_H \ No newline at end of file diff --git a/frameworks/native/hdi_returncode_transform.cpp b/frameworks/native/hdi_returncode_transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43d9c92b6b8e07d409c05db206c088319a2fcefb --- /dev/null +++ b/frameworks/native/hdi_returncode_transform.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "hdi_returncode_transform.h" +#include + +namespace OHOS { +namespace NeuralNetworkRuntime { +const std::unordered_map RET_STRING_MAP{ + {V2_0::NNRT_ReturnCode::NNRT_SUCCESS, "NNRT_SUCCESS"}, + {V2_0::NNRT_ReturnCode::NNRT_FAILED, "NNRT_FAILED"}, + {V2_0::NNRT_ReturnCode::NNRT_NULL_PTR, "NNRT_NULL_PTR"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_PARAMETER, "NNRT_INVALID_PARAMETER"}, + {V2_0::NNRT_ReturnCode::NNRT_MEMORY_ERROR, "NNRT_MEMORY_ERROR"}, + {V2_0::NNRT_ReturnCode::NNRT_OUT_OF_MEMORY, "NNRT_OUT_OF_MEMORY"}, + {V2_0::NNRT_ReturnCode::NNRT_OPERATION_FORBIDDEN, "NNRT_OPERATION_FORBIDDEN"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_FILE, "NNRT_INVALID_FILE"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_PATH, "NNRT_INVALID_PATH"}, + {V2_0::NNRT_ReturnCode::NNRT_INSUFFICIENT_BUFFER, "NNRT_INSUFFICIENT_BUFFER"}, + {V2_0::NNRT_ReturnCode::NNRT_NO_CHANGE, "NNRT_NO_CHANGE"}, + {V2_0::NNRT_ReturnCode::NNRT_NOT_SUPPORT, "NNRT_NOT_SUPPORT"}, + {V2_0::NNRT_ReturnCode::NNRT_SERVICE_ERROR, "NNRT_SERVICE_ERROR"}, + {V2_0::NNRT_ReturnCode::NNRT_DEVICE_ERROR, "NNRT_DEVICE_ERROR"}, + {V2_0::NNRT_ReturnCode::NNRT_DEVICE_BUSY, "NNRT_DEVICE_BUSY"}, + {V2_0::NNRT_ReturnCode::NNRT_CANCELLED, "NNRT_CANCELLED"}, + {V2_0::NNRT_ReturnCode::NNRT_PERMISSION_DENIED, "NNRT_PERMISSION_DENIED"}, + {V2_0::NNRT_ReturnCode::NNRT_TIME_OUT, "NNRT_TIME_OUT"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_TENSOR, "NNRT_INVALID_TENSOR"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_NODE, "NNRT_INVALID_NODE"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_INPUT, "NNRT_INVALID_INPUT"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_OUTPUT, "NNRT_INVALID_OUTPUT"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_DATATYPE, "NNRT_INVALID_DATATYPE"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_FORMAT, "NNRT_INVALID_FORMAT"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_TENSOR_NAME, "NNRT_INVALID_TENSOR_NAME"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_SHAPE, "NNRT_INVALID_SHAPE"}, + {V2_0::NNRT_ReturnCode::NNRT_OUT_OF_DIMENTION_RANGES, "NNRT_OUT_OF_DIMENTION_RANGES"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_BUFFER, "NNRT_INVALID_BUFFER"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_BUFFER_SIZE, "NNRT_INVALID_BUFFER_SIZE"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_PERFORMANCE_MODE, "NNRT_INVALID_PERFORMANCE_MODE"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_PRIORITY, "NNRT_INVALID_PRIORITY"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_MODEL, "NNRT_INVALID_MODEL"}, + {V2_0::NNRT_ReturnCode::NNRT_INVALID_MODEL_CACHE, "NNRT_INVALID_MODEL_CACHE"}, + {V2_0::NNRT_ReturnCode::NNRT_UNSUPPORTED_OP, "NNRT_UNSUPPORTED_OP"} +}; + +std::string ConverterRetToString(V2_0::NNRT_ReturnCode returnCode) +{ + if (RET_STRING_MAP.find(returnCode) == RET_STRING_MAP.end()) { + return ""; + } + + return RET_STRING_MAP.at(returnCode); +} +} +} \ No newline at end of file diff --git a/frameworks/native/hdi_interfaces.h b/frameworks/native/hdi_returncode_transform.h similarity index 63% rename from frameworks/native/hdi_interfaces.h rename to frameworks/native/hdi_returncode_transform.h index 1d3416ba6f9daff3cd10c3a5ea5bfa2bd02315d4..0d306c7fe9b12ea6a739cd2c7ff04b4d4a4ad8d6 100644 --- a/frameworks/native/hdi_interfaces.h +++ b/frameworks/native/hdi_returncode_transform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -13,17 +13,17 @@ * limitations under the License. */ -#ifndef NEURAL_NETWORK_RUNTIME_HDI_INTERFACES_H -#define NEURAL_NETWORK_RUNTIME_HDI_INTERFACES_H -#include -#include -#include +#ifndef NEURAL_NETWORK_RUNTIME_HDI_RETURNCODE_TRANSFORM_H +#define NEURAL_NETWORK_RUNTIME_HDI_RETURNCODE_TRANSFORM_H + +#include + +namespace V2_0 = OHOS::HDI::Nnrt::V2_0; namespace OHOS { namespace NeuralNetworkRuntime { -namespace V1_0 = OHOS::HDI::Nnrt::V1_0; +std::string ConverterRetToString(V2_0::NNRT_ReturnCode returnCode); } // namespace NeuralNetworkRuntime -} // namespace OHOS - -#endif // NEURAL_NETWORK_RUNTIME_HDI_INTERFACES_H \ No newline at end of file +} // OHOS +#endif // NEURAL_NETWORK_RUNTIME_HDI_RETURNCODE_TRANSFORM_H \ No newline at end of file diff --git a/frameworks/native/inner_model.cpp b/frameworks/native/inner_model.cpp index bcd20c6e2cf1feafc2e058ea790dce815363b03e..205222fa258f1c5535e9d09477c46bb6ec0fc143 100644 --- a/frameworks/native/inner_model.cpp +++ b/frameworks/native/inner_model.cpp @@ -24,7 +24,6 @@ #include "common/utils.h" #include "common/scoped_trace.h" #include "device_manager.h" -#include "hdi_device.h" #include "validation.h" #include "ops_builder.h" #include "ops_registry.h" diff --git a/frameworks/native/ops/cast_builder.cpp b/frameworks/native/ops/cast_builder.cpp index 81dc1eb2b5f386bbf04fa022649b8dba146b4438..6336926209671c077fe40afd083ba5cfaab5f097 100644 --- a/frameworks/native/ops/cast_builder.cpp +++ b/frameworks/native/ops/cast_builder.cpp @@ -57,7 +57,6 @@ OH_NN_ReturnCode CastBuilder::Build(const std::vector& paramsIndex, LOGE("[Cast] Type of cast operator is not validation."); return OH_NN_INVALID_PARAMETER; } - *castTypeInt = (OH_NN_DataType)NNToHDI::TransDataType(*castTypeInt); if (!paramsIndex.empty()) { LOGE("[Cast] Cast expects no parameters"); diff --git a/frameworks/native/prepared_model.h b/frameworks/native/prepared_model.h index 65741311a999d456487091e11fc54e2f2c4641b1..2d25f6fbf0e33e0cdf6a43cab392db3676f40b29 100644 --- a/frameworks/native/prepared_model.h +++ b/frameworks/native/prepared_model.h @@ -34,6 +34,10 @@ public: const std::vector& outputs, std::vector>& outputsDims, std::vector& isOutputBufferEnough) = 0; + + virtual OH_NN_ReturnCode GetInputDimRanges( + std::vector>& minInputDims, + std::vector>& maxInputDims) { return OH_NN_OPERATION_FORBIDDEN; } }; } // OHOS } // namespace NeuralNetworkRuntime diff --git a/frameworks/native/transform.cpp b/frameworks/native/transform.cpp index ea0d3391a84757016eb600c0e782642a768cd627..d3705d5381f93b45c79d0def51b688b8608adf5f 100644 --- a/frameworks/native/transform.cpp +++ b/frameworks/native/transform.cpp @@ -25,134 +25,6 @@ const uint32_t BIT16_TO_BYTE = 2; const uint32_t BIT32_TO_BYTE = 4; const uint32_t BIT64_TO_BYTE = 8; -OH_NN_DeviceType HDIToNN::TransHDIDeviceType(const V1_0::DeviceType& iDeviceType) -{ - switch (iDeviceType) { - case V1_0::DeviceType::CPU: - return OH_NN_CPU; - case V1_0::DeviceType::GPU: - return OH_NN_GPU; - case V1_0::DeviceType::ACCELERATOR: - return OH_NN_ACCELERATOR; - default: - return OH_NN_OTHERS; - } -} - -DeviceStatus HDIToNN::TransHDIDeviceStatus(const V1_0::DeviceStatus& iDeviceStatus) -{ - switch (iDeviceStatus) { - case V1_0::DeviceStatus::AVAILABLE: - return DeviceStatus::AVAILABLE; - case V1_0::DeviceStatus::BUSY: - return DeviceStatus::BUSY; - case V1_0::DeviceStatus::OFFLINE: - return DeviceStatus::OFFLINE; - default: - return DeviceStatus::UNKNOWN; - } -} - -V1_0::PerformanceMode NNToHDI::TransPerformanceMode(const OH_NN_PerformanceMode& mode) -{ - switch (mode) { - case OH_NN_PERFORMANCE_LOW: - return V1_0::PerformanceMode::PERFORMANCE_LOW; - case OH_NN_PERFORMANCE_MEDIUM: - return V1_0::PerformanceMode::PERFORMANCE_MEDIUM; - case OH_NN_PERFORMANCE_HIGH: - return V1_0::PerformanceMode::PERFORMANCE_HIGH; - case OH_NN_PERFORMANCE_EXTREME: - return V1_0::PerformanceMode::PERFORMANCE_EXTREME; - default: - return V1_0::PerformanceMode::PERFORMANCE_NONE; - } -} -V1_0::Priority NNToHDI::TransPriority(const OH_NN_Priority& priority) -{ - switch (priority) { - case OH_NN_PRIORITY_LOW: - return V1_0::Priority::PRIORITY_LOW; - case OH_NN_PRIORITY_MEDIUM: - return V1_0::Priority::PRIORITY_MEDIUM; - case OH_NN_PRIORITY_HIGH: - return V1_0::Priority::PRIORITY_HIGH; - default: - return V1_0::Priority::PRIORITY_NONE; - } -} - -V1_0::DataType NNToHDI::TransDataType(const OH_NN_DataType& dataType) -{ - switch (dataType) { - case OH_NN_BOOL: - return V1_0::DataType::DATA_TYPE_BOOL; - case OH_NN_INT8: - return V1_0::DataType::DATA_TYPE_INT8; - case OH_NN_INT16: - return V1_0::DataType::DATA_TYPE_INT16; - case OH_NN_INT32: - return V1_0::DataType::DATA_TYPE_INT32; - case OH_NN_INT64: - return V1_0::DataType::DATA_TYPE_INT64; - case OH_NN_UINT8: - return V1_0::DataType::DATA_TYPE_UINT8; - case OH_NN_UINT16: - return V1_0::DataType::DATA_TYPE_UINT16; - case OH_NN_UINT32: - return V1_0::DataType::DATA_TYPE_UINT32; - case OH_NN_UINT64: - return V1_0::DataType::DATA_TYPE_UINT64; - case OH_NN_FLOAT16: - return V1_0::DataType::DATA_TYPE_FLOAT16; - case OH_NN_FLOAT32: - return V1_0::DataType::DATA_TYPE_FLOAT32; - case OH_NN_FLOAT64: - return V1_0::DataType::DATA_TYPE_FLOAT64; - default: - return V1_0::DataType::DATA_TYPE_UNKNOWN; - } -} - -V1_0::Format NNToHDI::TransFormat(const OH_NN_Format& format) -{ - switch (format) { - case OH_NN_FORMAT_NCHW: - return V1_0::Format::FORMAT_NCHW; - case OH_NN_FORMAT_NHWC: - return V1_0::Format::FORMAT_NHWC; - default: - return V1_0::Format::FORMAT_NONE; - } -} - -V1_0::IOTensor NNToHDI::TransIOTensor(const IOTensor& tensor) -{ - V1_0::IOTensor iTensor; - iTensor.name = tensor.name; - iTensor.dataType = TransDataType(tensor.dataType); - iTensor.dimensions = tensor.dimensions; - iTensor.format = TransFormat(tensor.format); - - V1_0::SharedBuffer iBuffer {INVALID_FD, 0, 0, 0}; - if (tensor.data != nullptr) { - auto memManager = MemoryManager::GetInstance(); - Memory memory; - auto ret = memManager->GetMemory(tensor.data, memory); - if (ret != OH_NN_SUCCESS) { - LOGE("Invalid Tensor buffer, cannot transform to fd."); - } else { - iBuffer.fd = memory.fd; - iBuffer.bufferSize = memory.length; - iBuffer.offset = 0; - iBuffer.dataSize = memory.length; - } - } - iTensor.data = iBuffer; - - return iTensor; -} - uint32_t GetTypeSize(OH_NN_DataType type) { switch (type) { diff --git a/frameworks/native/transform.h b/frameworks/native/transform.h index 2472ad3f8d1ca8e77912ac3e4f521d7ce7825c1b..24d54e8d351dc7cf9a05e70eceea8cc365412daa 100644 --- a/frameworks/native/transform.h +++ b/frameworks/native/transform.h @@ -16,7 +16,6 @@ #ifndef NEURAL_NETWORK_RUNTIME_TRANSFORM_H #define NEURAL_NETWORK_RUNTIME_TRANSFORM_H -#include "hdi_interfaces.h" #include "interfaces/kits/c/neural_network_runtime_type.h" #include "cpp_type.h" #include "mindir.h" @@ -38,19 +37,6 @@ std::vector ConstructVectorFromArray(const T* data, size_t size) uint32_t GetTypeSize(OH_NN_DataType type); -namespace HDIToNN { -OH_NN_DeviceType TransHDIDeviceType(const V1_0::DeviceType& iDeviceType); -DeviceStatus TransHDIDeviceStatus(const V1_0::DeviceStatus& iDeviceStatus); -} // namespace HDIToNN - -namespace NNToHDI { -V1_0::PerformanceMode TransPerformanceMode(const OH_NN_PerformanceMode& mode); -V1_0::Priority TransPriority(const OH_NN_Priority& priority); -V1_0::DataType TransDataType(const OH_NN_DataType& dataType); -V1_0::Format TransFormat(const OH_NN_Format& format); -V1_0::IOTensor TransIOTensor(const IOTensor& tensor); -} // namespace NNToHDI - namespace NNToMS { mindspore::lite::DataType TransformDataType(OH_NN_DataType type); mindspore::lite::Format TransformFormat(OH_NN_Format type);