diff --git a/cmake/mind_expression.cmake b/cmake/mind_expression.cmake index e7aa6ac3f4ac8768e1b0116cd904ffb2e0518728..a3a469c27042c596fb687ff673148abf07b1904f 100644 --- a/cmake/mind_expression.cmake +++ b/cmake/mind_expression.cmake @@ -15,7 +15,7 @@ include(${CMAKE_SOURCE_DIR}/cmake/external_libs/json.cmake) include(${CMAKE_SOURCE_DIR}/cmake/dependency_securec.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/protobuf.cmake) -if (ENABLE_DEBUGGER OR ENABLE_SERVING) +if (ENABLE_DEBUGGER OR ENABLE_SERVING OR ENABLE_TESTCASES) # build dependencies of gRPC include(${CMAKE_SOURCE_DIR}/cmake/external_libs/absl.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/c-ares.cmake) @@ -69,7 +69,6 @@ endif() if (ENABLE_MINDDATA) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/icu4c.cmake) - include(${CMAKE_SOURCE_DIR}/cmake/external_libs/jpeg_turbo.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/libtiff.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/opencv.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/sqlite.cmake) @@ -78,6 +77,10 @@ if (ENABLE_MINDDATA) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/sentencepiece.cmake) endif() +if (ENABLE_MINDDATA OR ENABLE_SERVING) + include(${CMAKE_SOURCE_DIR}/cmake/external_libs/jpeg_turbo.cmake) +endif() + include(${CMAKE_SOURCE_DIR}/cmake/external_libs/gtest.cmake) include(${CMAKE_SOURCE_DIR}/cmake/external_libs/onnx.cmake) set(CMAKE_CXX_FLAGS ${_ms_tmp_CMAKE_CXX_FLAGS_F}) diff --git a/include/infer_log.h b/include/infer_log.h index 541b6fdd261c03656acb340dafdd1b978f1e2dc9..869588bda3a220cfa89673dae1e30875b4f9e415 100644 --- a/include/infer_log.h +++ b/include/infer_log.h @@ -26,19 +26,10 @@ #ifndef ENABLE_ACL #include "mindspore/core/utils/log_adapter.h" -namespace mindspore::inference { -#define MSI_LOG(level) MS_LOG(level) - -#define MSI_LOG_DEBUG MSI_LOG(DEBUG) -#define MSI_LOG_INFO MSI_LOG(INFO) -#define MSI_LOG_WARNING MSI_LOG(WARNING) -#define MSI_LOG_ERROR MSI_LOG(ERROR) - -#define MSI_ASSERT(item) MS_ASSERT(item) -} // namespace mindspore::inference - #else // ENABLE_ACL #include "acl/acl.h" +#endif + namespace mindspore::inference { class LogStream { @@ -58,15 +49,23 @@ class LogStream { } friend class LogWriter; + friend class Status; private: std::shared_ptr sstream_; }; -template ::value, int>::type = 0> -constexpr std::ostream &operator<<(std::ostream &stream, const T &value) { - return stream << static_cast::type>(value); -} +#ifndef ENABLE_ACL +#define MSI_LOG(level) MS_LOG(level) + +#define MSI_LOG_DEBUG MSI_LOG(DEBUG) +#define MSI_LOG_INFO MSI_LOG(INFO) +#define MSI_LOG_WARNING MSI_LOG(WARNING) +#define MSI_LOG_ERROR MSI_LOG(ERROR) + +#define MSI_ASSERT(item) MS_ASSERT(item) + +#else // ENABLE_ACL class LogWriter { public: @@ -100,8 +99,10 @@ class LogWriter { #define MSI_ASSERT(item) -} // namespace mindspore::inference - #endif // ENABLE_ACL +#define INFER_STATUS(code) inference::Status(code) < inference::LogStream() + +} // namespace mindspore::inference + #endif // MINDSPORE_INFERENCE_LOG_H_ diff --git a/include/infer_tensor.h b/include/infer_tensor.h index 1fce1e1a329191c530de9764956fee51e5e20693..7aed3e9a474ac217e503cb1b08ad14629baa20bc 100644 --- a/include/infer_tensor.h +++ b/include/infer_tensor.h @@ -129,12 +129,25 @@ class InferTensor : public InferTensorBase { void *mutable_data() override { return data_.data(); } }; +class InferImagesBase { + public: + virtual size_t batch_size() const = 0; + virtual bool get(size_t index, const void *&pic_buffer, uint32_t &pic_size) const = 0; + virtual size_t input_index() const = 0; // the index of images as input in model +}; + class RequestBase { public: virtual size_t size() const = 0; virtual const InferTensorBase *operator[](size_t index) const = 0; }; +class ImagesRequestBase { + public: + virtual size_t size() const = 0; + virtual const InferImagesBase *operator[](size_t index) const = 0; +}; + class ReplyBase { public: virtual size_t size() const = 0; diff --git a/include/inference.h b/include/inference.h index 082cae5d5c8d3d92686a498e852f66973ad05d07..8598401b757946709a67e46614816b4e3a99cb08 100644 --- a/include/inference.h +++ b/include/inference.h @@ -21,10 +21,36 @@ #include #include #include "include/infer_tensor.h" +#include "include/infer_log.h" namespace mindspore { namespace inference { -enum Status { SUCCESS = 0, FAILED, INVALID_INPUTS }; + +enum StatusCode { SUCCESS = 0, FAILED, INVALID_INPUTS }; + +class Status { + public: + Status() : status_code_(FAILED) {} + Status(enum StatusCode status_code, const std::string &status_msg = "") + : status_code_(status_code), status_msg_(status_msg) {} + bool IsSuccess() const { return status_code_ == SUCCESS; } + enum StatusCode StatusCode() const { return status_code_; } + std::string StatusMessage() const { return status_msg_; } + bool operator==(const Status &other) const { return status_code_ == other.status_code_; } + bool operator==(enum StatusCode other_code) const { return status_code_ == other_code; } + bool operator!=(const Status &other) const { return status_code_ != other.status_code_; } + bool operator!=(enum StatusCode other_code) const { return status_code_ != other_code; } + operator bool() const = delete; + Status &operator<(const LogStream &stream) noexcept __attribute__((visibility("default"))) { + status_msg_ = stream.sstream_->str(); + return *this; + } + + private: + enum StatusCode status_code_; + std::string status_msg_; +}; + class MS_API InferSession { public: InferSession() = default; @@ -42,7 +68,12 @@ class MS_API InferSession { VectorInferTensorWrapReply reply(outputs); return ExecuteModel(model_id, request, reply); } - + // default not support input data preprocess(decode, resize, crop, crop&paste, etc.) + virtual Status ExecuteModel(uint32_t /*model_id*/, + const ImagesRequestBase & /*images_inputs*/, // images for preprocess + const RequestBase & /*request*/, ReplyBase & /*reply*/) { + return FAILED; + } static std::shared_ptr CreateSession(const std::string &device, uint32_t device_id); }; diff --git a/mindspore/ccsrc/backend/session/ascend_inference_session.cc b/mindspore/ccsrc/backend/session/ascend_inference_session.cc index ef796ff4fdcb3ae93d6d89b62d652a950e4a8e30..4d5d9aa0b1ca2eaf9c5d60ae46a3fc4d685db5e1 100644 --- a/mindspore/ccsrc/backend/session/ascend_inference_session.cc +++ b/mindspore/ccsrc/backend/session/ascend_inference_session.cc @@ -87,7 +87,8 @@ GraphId AscendInferenceSession::CompileGraph(NotNull func_graph) { return graph_id; } -bool AscendInferenceSession::CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const { +bool AscendInferenceSession::CheckModelInputs(uint32_t graph_id, const std::vector &inputs, + std::string *error_msg) const { MS_LOG(INFO) << "Start check client inputs, graph id : " << graph_id; auto kernel_graph = GetGraph(graph_id); MS_EXCEPTION_IF_NULL(kernel_graph); @@ -113,12 +114,25 @@ bool AscendInferenceSession::CheckModelInputs(uint32_t graph_id, const std::vect MS_LOG(ERROR) << "Input number is inconsistent. The actual input number [" << inputs.size() << "] but the graph input number is [" << paras.size() << "]"; MS_LOG(ERROR) << "InputsInfo --" << InputsInfo(paras, inputs); + if (error_msg != nullptr) { + std::stringstream str_stream; + str_stream << "Input number is inconsistent. The given input number [" << inputs.size() + << "] but the graph input number is [" << paras.size() << "]\n"; + str_stream << "InputsInfo --" << InputsInfo(paras, inputs); + *error_msg = str_stream.str(); + } return false; } auto input = inputs[no_weight_input++]; if (!CompareInput(input, paras[i])) { MS_LOG(ERROR) << "Please check the input information."; MS_LOG(ERROR) << "InputsInfo --" << InputsInfo(paras, inputs); + if (error_msg != nullptr) { + std::stringstream str_stream; + str_stream << "Please check the input information.\n"; + str_stream << "InputsInfo --" << InputsInfo(paras, inputs); + *error_msg = str_stream.str(); + } return false; } } @@ -165,17 +179,35 @@ std::string AscendInferenceSession::PrintInputShape(std::vector shape) const std::string AscendInferenceSession::InputsInfo(const std::vector ¶s, const std::vector &inputs) const { + const std::map dtype_name_map{ + {TypeId::kNumberTypeBegin, "Unknown"}, {TypeId::kNumberTypeBool, "Bool"}, + {TypeId::kNumberTypeFloat64, "Float64"}, {TypeId::kNumberTypeInt8, "Int8"}, + {TypeId::kNumberTypeUInt8, "Uint8"}, {TypeId::kNumberTypeInt16, "Int16"}, + {TypeId::kNumberTypeUInt16, "Uint16"}, {TypeId::kNumberTypeInt32, "Int32"}, + {TypeId::kNumberTypeUInt32, "Uint32"}, {TypeId::kNumberTypeInt64, "Int64"}, + {TypeId::kNumberTypeUInt64, "Uint64"}, {TypeId::kNumberTypeFloat16, "Float16"}, + {TypeId::kNumberTypeFloat32, "Float32"}, + }; + auto data_type_to_string = [&dtype_name_map](TypeId type_id) { + auto it = dtype_name_map.find(type_id); + if (it == dtype_name_map.end()) { + return std::string("Unknown"); + } + return it->second; + }; + std::string graph = "graph inputs:{ "; for (size_t i = 0; i < paras.size(); ++i) { - graph += std::to_string(i) + ": dims " + std::to_string(AnfAlgo::GetOutputDeviceShape(paras[i], 0).size()) + - ", shape " + PrintInputShape(AnfAlgo::GetOutputDeviceShape(paras[i], 0)) + ", data type " + - std::to_string(AnfAlgo::GetSelectKernelBuildInfo(paras[i])->GetOutputDeviceType(0)) + " }"; + auto ¶ = paras[i]; + graph += std::to_string(i) + ": dims " + std::to_string(AnfAlgo::GetOutputDeviceShape(para, 0).size()) + + ", shape " + PrintInputShape(AnfAlgo::GetOutputDeviceShape(para, 0)) + ", data type " + + data_type_to_string(AnfAlgo::GetSelectKernelBuildInfo(para)->GetOutputDeviceType(0)) + " }"; } - std::string actual = "actual inputs:{ "; + std::string actual = "given inputs:{ "; for (size_t i = 0; i < inputs.size(); ++i) { actual += std::to_string(i) + ": dims " + std::to_string(inputs[i]->shape().size()) + ", shape " + - PrintInputShape(inputs[i]->shape()) + ", data type " + std::to_string(inputs[i]->data_type()) + " }"; + PrintInputShape(inputs[i]->shape()) + ", data type " + data_type_to_string(inputs[i]->data_type()) + " }"; } return graph + " " + actual; } diff --git a/mindspore/ccsrc/backend/session/ascend_inference_session.h b/mindspore/ccsrc/backend/session/ascend_inference_session.h index 976ce7b63fb712dcddcf00a1e841965c3daa68ed..d092b3ccb3fc48cf4bbefa2e5efd1db336e955e0 100644 --- a/mindspore/ccsrc/backend/session/ascend_inference_session.h +++ b/mindspore/ccsrc/backend/session/ascend_inference_session.h @@ -39,7 +39,8 @@ class AscendInferenceSession : public AscendSession { void LoadInputData(const std::shared_ptr &kernel_graph, const std::vector &inputs_const) const; GraphId CompileGraph(NotNull func_graph) override; - bool CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const override; + bool CheckModelInputs(uint32_t graph_id, const std::vector &inputs, + std::string *error_msg) const override; bool CompareInput(const tensor::TensorPtr &input, const ParameterPtr ¶meter) const; template std::string PrintInputShape(std::vector shape) const; diff --git a/mindspore/ccsrc/backend/session/infer_session.cc b/mindspore/ccsrc/backend/session/infer_session.cc index cec532fc8cc802eec2b7fcfd2340d72929d1cdac..3e58200b28b750ab1f9aa91bb13a47bb4ea3e355 100644 --- a/mindspore/ccsrc/backend/session/infer_session.cc +++ b/mindspore/ccsrc/backend/session/infer_session.cc @@ -116,7 +116,7 @@ Status MSInferSession::LoadModelFromFile(const std::string &file_name, uint32_t Status MSInferSession::UnloadModel(uint32_t model_id) { return SUCCESS; } -tensor::TensorPtr ServingTensor2MSTensor(const InferTensorBase &out_tensor) { +Status ServingTensor2MSTensor(size_t index, const InferTensorBase &out_tensor, tensor::TensorPtr &ms_tensor) { std::vector shape; for (auto dim : out_tensor.shape()) { shape.push_back(static_cast(dim)); @@ -134,14 +134,22 @@ tensor::TensorPtr ServingTensor2MSTensor(const InferTensorBase &out_tensor) { auto it = type2id_map.find(out_tensor.data_type()); if (it == type2id_map.end()) { MSI_LOG_WARNING << "undefined MSI data type " << out_tensor.data_type(); - return nullptr; + return FAILED; } else { data_type = it->second; } - auto ms_tensor = std::make_shared(data_type, shape); + ms_tensor = std::make_shared(data_type, shape); + if (ms_tensor->Size() != out_tensor.data_size()) { + MSI_LOG_ERROR << "input " << std::to_string(index) + << " data size not match shape and dtype, calculated required size " << ms_tensor->Size() + << ", given " << out_tensor.data_size(); + return INFER_STATUS(INVALID_INPUTS) << "input " << std::to_string(index) + << " data size not match shape and dtype, calculated required size " + << ms_tensor->Size() << ", given " << out_tensor.data_size(); + } memcpy_s(ms_tensor->data_c(), ms_tensor->Size(), out_tensor.data(), out_tensor.data_size()); - return ms_tensor; + return SUCCESS; } void MSTensor2ServingTensor(tensor::TensorPtr ms_tensor, InferTensorBase &out_tensor) { @@ -189,16 +197,18 @@ Status MSInferSession::ExecuteModel(uint32_t model_id, const RequestBase &reques MS_LOG(ERROR) << "Execute Model " << model_id << " Failed, input tensor is null, index " << i; return FAILED; } - auto input = ServingTensor2MSTensor(*request[i]); - if (input == nullptr) { + tensor::TensorPtr input = nullptr; + auto ret = ServingTensor2MSTensor(i, *request[i], input); + if (ret != SUCCESS) { MS_LOG(ERROR) << "Tensor convert failed"; - return FAILED; + return ret; } inputs.push_back(input); } - if (!CheckModelInputs(model_id, inputs)) { + auto ret = CheckModelInputs(model_id, inputs); + if (ret != SUCCESS) { MS_LOG(ERROR) << "Check Model " << model_id << " Inputs Failed"; - return INVALID_INPUTS; + return ret; } vector outputs = RunGraph(model_id, inputs); if (outputs.empty()) { @@ -354,9 +364,13 @@ Status MSInferSession::InitEnv(const std::string &device, uint32_t device_id) { return SUCCESS; } -bool MSInferSession::CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const { +Status MSInferSession::CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const { MS_ASSERT(session_impl_ != nullptr); - return session_impl_->CheckModelInputs(graph_id, inputs); + std::string error_msg; + if (!session_impl_->CheckModelInputs(graph_id, inputs, &error_msg)) { + return INFER_STATUS(INVALID_INPUTS) << error_msg; + } + return SUCCESS; } } // namespace mindspore::inference diff --git a/mindspore/ccsrc/backend/session/infer_session.h b/mindspore/ccsrc/backend/session/infer_session.h index 62ed5f9ff4a052285018f1693a8c269b0cb02267..c58e16e3821b20440f28b04367b000b938512802 100644 --- a/mindspore/ccsrc/backend/session/infer_session.h +++ b/mindspore/ccsrc/backend/session/infer_session.h @@ -58,7 +58,7 @@ class MSInferSession : public InferSession { static void RegAllOp(); string AjustTargetName(const std::string &device); Status CompileGraph(std::shared_ptr funcGraphPtr, uint32_t &model_id); - bool CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const; + Status CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const; std::vector RunGraph(uint32_t graph_id, const std::vector &inputs); }; } // namespace inference diff --git a/mindspore/ccsrc/backend/session/session_basic.h b/mindspore/ccsrc/backend/session/session_basic.h index 5f3a0cab926a5c4e3a49ef7da0319e14faf502af..c5dea49b6c82df4460b8a1253d07788e2eff89a2 100755 --- a/mindspore/ccsrc/backend/session/session_basic.h +++ b/mindspore/ccsrc/backend/session/session_basic.h @@ -97,7 +97,10 @@ class SessionBasic { virtual GraphId GetFinalRunGraph() const { return kInvalidGraphId; } void AssignParamKey(const KernelGraphPtr &kernel_graph); void InitPSParamAndOptim(const KernelGraphPtr &kernel_graph, const std::vector &inputs_const); - virtual bool CheckModelInputs(uint32_t graph_id, const std::vector &inputs) const { return true; } + virtual bool CheckModelInputs(uint32_t graph_id, const std::vector &inputs, + std::string *error_msg) const { + return true; + } #ifdef ENABLE_DEBUGGER // set debugger diff --git a/serving/CMakeLists.txt b/serving/CMakeLists.txt index 5c5032e4a87a0f166186f8c5d72dab9a712f917c..8b60168228a41bd6ba784cbc5f646f3c1f919a1e 100644 --- a/serving/CMakeLists.txt +++ b/serving/CMakeLists.txt @@ -103,9 +103,12 @@ endif () if (ENABLE_ACL) add_compile_definitions(ENABLE_ACL) + add_compile_definitions(ENABLE_DVPP_INTERFACE) set(ALC_LIB_SO ${ACL_LIB_DIR}/lib64/libruntime.so ${ACL_LIB_DIR}/lib64/libascendcl.so - ${ACL_LIB_DIR}/lib64/libacl_retr.so ${ACL_LIB_DIR}/lib64/libacl_cblas.so) + ${ACL_LIB_DIR}/lib64/libacl_retr.so ${ACL_LIB_DIR}/lib64/libacl_cblas.so + ${ACL_LIB_DIR}/lib64/libacl_dvpp.so) target_link_libraries(ms_serving ${ALC_LIB_SO}) + target_link_libraries(ms_serving jpeg_turbo::jpeg) else () target_link_libraries(ms_serving inference mindspore_gvar) endif () diff --git a/serving/acl/acl_session.cc b/serving/acl/acl_session.cc index d154cc7164d053561a55fcb1f7100ca0e9c5c567..92444924eb14de8a21760424059f992653ef75e1 100644 --- a/serving/acl/acl_session.cc +++ b/serving/acl/acl_session.cc @@ -16,6 +16,7 @@ #include #include +#include #include "serving/acl/acl_session.h" #include "include/infer_log.h" @@ -25,7 +26,7 @@ std::shared_ptr InferSession::CreateSession(const std::string &dev try { auto session = std::make_shared(); auto ret = session->InitEnv(device, device_id); - if (!ret) { + if (ret != SUCCESS) { return nullptr; } return session; @@ -36,22 +37,123 @@ std::shared_ptr InferSession::CreateSession(const std::string &dev } Status AclSession::LoadModelFromFile(const std::string &file_name, uint32_t &model_id) { - return model_process_.LoadModelFromFile(file_name, model_id) ? SUCCESS : FAILED; + Status ret = model_process_.LoadModelFromFile(file_name, model_id); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Load model from file failed, model file " << file_name; + return FAILED; + } + std::string dvpp_config_file; + auto index = file_name.rfind("."); + if (index == std::string::npos) { + dvpp_config_file = file_name; + } else { + dvpp_config_file = file_name.substr(0, index); + } + dvpp_config_file += "_dvpp_config.json"; + std::ifstream fp(dvpp_config_file); + if (!fp.is_open()) { + MSI_LOG_INFO << "Dvpp config file not exist, model will execute with tensors as inputs, dvpp config file " + << dvpp_config_file; + return SUCCESS; + } + fp.close(); + if (dvpp_process_.InitWithJsonConfig(dvpp_config_file) != SUCCESS) { + MSI_LOG_ERROR << "Dvpp config file parse error, dvpp config file " << dvpp_config_file; + return FAILED; + } + execute_with_dvpp_ = true; + MSI_LOG_INFO << "Dvpp config success"; + return SUCCESS; } -Status AclSession::UnloadModel(uint32_t model_id) { +Status AclSession::UnloadModel(uint32_t /*model_id*/) { model_process_.UnLoad(); return SUCCESS; } -Status AclSession::ExecuteModel(uint32_t model_id, const RequestBase &request, +Status AclSession::ExecuteModel(uint32_t /*model_id*/, const RequestBase &request, ReplyBase &reply) { // set d context aclError rt_ret = aclrtSetCurrentContext(context_); if (rt_ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "set the ascend device context failed"; return FAILED; } - return model_process_.Execute(request, reply) ? SUCCESS : FAILED; + return model_process_.Execute(request, reply); +} + +Status AclSession::PreProcess(uint32_t /*model_id*/, const InferImagesBase *images_input, + ImagesDvppOutput &dvpp_output) { + if (images_input == nullptr) { + MSI_LOG_ERROR << "images input is nullptr"; + return FAILED; + } + auto batch_size = images_input->batch_size(); + if (batch_size <= 0) { + MSI_LOG_ERROR << "invalid batch size " << images_input->batch_size(); + return FAILED; + } + std::vector pic_buffer_list; + std::vector pic_size_list; + for (size_t i = 0; i < batch_size; i++) { + const void *pic_buffer = nullptr; + uint32_t pic_size = 0; + if (!images_input->get(i, pic_buffer, pic_size) || pic_buffer == nullptr || pic_size == 0) { + MSI_LOG_ERROR << "Get request " << 0 << "th buffer failed"; + return FAILED; + } + pic_buffer_list.push_back(pic_buffer); + pic_size_list.push_back(pic_size); + } + auto ret = dvpp_process_.Process(pic_buffer_list, pic_size_list, dvpp_output.buffer_device, dvpp_output.buffer_size); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "dvpp process failed"; + return ret; + } + return SUCCESS; +} + +Status AclSession::ExecuteModel(uint32_t model_id, const ImagesRequestBase &images_inputs, // images for preprocess + const RequestBase &request, ReplyBase &reply) { + if (!execute_with_dvpp_) { + MSI_LOG_ERROR << "Unexpected images as inputs, DVPP not config"; + return INFER_STATUS(INVALID_INPUTS) << "Unexpected images as inputs, DVPP not config"; + } + aclError rt_ret = aclrtSetCurrentContext(context_); + if (rt_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "set the ascend device context failed"; + return FAILED; + } + if (images_inputs.size() != 1) { + MSI_LOG_ERROR << "Only support one input to do DVPP preprocess"; + return INFER_STATUS(INVALID_INPUTS) << "Only support one input to do DVPP preprocess"; + } + if (images_inputs[0] == nullptr) { + MSI_LOG_ERROR << "Get first images input failed"; + return FAILED; + } + if (images_inputs[0]->batch_size() != model_process_.GetBatchSize()) { + MSI_LOG_ERROR << "Input batch size " << images_inputs[0]->batch_size() << " not match Model batch size " + << model_process_.GetBatchSize(); + return INFER_STATUS(INVALID_INPUTS) << "Input batch size " << images_inputs[0]->batch_size() + << " not match Model batch size " << model_process_.GetBatchSize(); + } + if (request.size() != 0) { + MSI_LOG_ERROR << "only support one input, images input size is 1, tensor inputs is not 0 " << request.size(); + return INFER_STATUS(INVALID_INPUTS) << "only support one input, images input size is 1, tensor inputs is not 0 " + << request.size(); + } + ImagesDvppOutput dvpp_output; + Status ret = PreProcess(model_id, images_inputs[0], dvpp_output); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "DVPP preprocess failed"; + return ret; + } + ret = model_process_.Execute(dvpp_output.buffer_device, dvpp_output.buffer_size, reply); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Execute model failed"; + return ret; + } + return SUCCESS; } Status AclSession::InitEnv(const std::string &device_type, uint32_t device_id) { @@ -95,11 +197,16 @@ Status AclSession::InitEnv(const std::string &device_type, uint32_t device_id) { model_process_.SetIsDevice(is_device); MSI_LOG_INFO << "get run mode success is device input/output " << is_device; + if (dvpp_process_.InitResource(stream_) != SUCCESS) { + MSI_LOG_ERROR << "dvpp init resource failed"; + return FAILED; + } MSI_LOG_INFO << "Init acl success, device id " << device_id_; return SUCCESS; } Status AclSession::FinalizeEnv() { + dvpp_process_.Finalize(); aclError ret; if (stream_ != nullptr) { ret = aclrtDestroyStream(stream_); diff --git a/serving/acl/acl_session.h b/serving/acl/acl_session.h index 2b44f9e1d58f0361b1744601bbce92c4cf1d8205..c1ae025df2e61ea61c5f4d09448e67752dd8ea92 100644 --- a/serving/acl/acl_session.h +++ b/serving/acl/acl_session.h @@ -25,9 +25,11 @@ #include "include/inference.h" #include "serving/acl/model_process.h" +#include "serving/acl/dvpp_process.h" namespace mindspore { namespace inference { + class AclSession : public InferSession { public: AclSession(); @@ -37,6 +39,8 @@ class AclSession : public InferSession { Status LoadModelFromFile(const std::string &file_name, uint32_t &model_id) override; Status UnloadModel(uint32_t model_id) override; Status ExecuteModel(uint32_t model_id, const RequestBase &request, ReplyBase &reply) override; + Status ExecuteModel(uint32_t model_id, const ImagesRequestBase &images_inputs, // images for preprocess + const RequestBase &request, ReplyBase &reply) override; private: std::string device_type_; @@ -44,6 +48,10 @@ class AclSession : public InferSession { aclrtStream stream_ = nullptr; aclrtContext context_ = nullptr; ModelProcess model_process_; + bool execute_with_dvpp_ = false; + DvppProcess dvpp_process_; + + Status PreProcess(uint32_t model_id, const InferImagesBase *images_input, ImagesDvppOutput &dvpp_output); }; } // namespace inference } // namespace mindspore diff --git a/serving/acl/dvpp_process.cc b/serving/acl/dvpp_process.cc new file mode 100644 index 0000000000000000000000000000000000000000..1fedaf640644b93704d513f998804a1f871069a1 --- /dev/null +++ b/serving/acl/dvpp_process.cc @@ -0,0 +1,1139 @@ +/** + * Copyright 2020 Huawei Technologies 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 "serving/acl/dvpp_process.h" +#include +#include +#include +#include +#include "include/infer_log.h" + +namespace mindspore { +namespace inference { + +DvppProcess::DvppProcess() {} + +DvppProcess::~DvppProcess() {} + +static uint32_t ToEven(uint32_t num) { return (num + 1) / 2 * 2; } + +static uint32_t ToOdd(uint32_t num) { + if (num == 0) { + return 1; + } + return (num + 1) / 2 * 2 - 1; +} + +class DvppJsonConfigParser { + public: + DvppJsonConfigParser() = default; + ~DvppJsonConfigParser() = default; + + Status InitWithJsonConfig(const std::string &json_config); + DvppDecodePara GetDecodePara() const { return decode_para_; } + DvppResizePara GetResizePara() const { return resize_para_; } + DvppCropPara GetCropPara() const { return crop_para_; } + DvppCropAndPastePara GetCropAndPastePara() const { return crop_and_paste_para_; } + bool HasResizeConfig() const { return resize_flag_; } + bool HasCropConfig() const { return crop_flag_; } + bool HasCropAndPasteConfig() const { return crop_and_paste_flag_; } + + private: + DvppDecodePara decode_para_; + DvppResizePara resize_para_; + DvppCropPara crop_para_; + DvppCropAndPastePara crop_and_paste_para_; + bool resize_flag_ = false; + bool crop_flag_ = false; + bool crop_and_paste_flag_ = false; + + Status GetStringValue(const nlohmann::json &json_item, const std::string &key, std::string &val); + Status GetIntValue(const nlohmann::json &json_item, const std::string &key, uint32_t &val); + Status ParseInputPara(const nlohmann::json &preprocess_item); + Status ParseDecodePara(const nlohmann::json &preprocess_item); + Status ParseResizePara(const nlohmann::json &json_item); + Status ParseCropPara(const nlohmann::json &json_item); + Status ParseCropAndPastePara(const nlohmann::json &json_item); + Status InitWithJsonConfigImp(const std::string &json_config); +}; + +Status DvppProcess::InitResource(aclrtStream stream) { + stream_ = stream; + aclError acl_ret; + dvpp_channel_desc_ = acldvppCreateChannelDesc(); + if (dvpp_channel_desc_ == nullptr) { + MSI_LOG_ERROR << "acldvppCreateChannelDesc failed"; + return FAILED; + } + acl_ret = acldvppCreateChannel(dvpp_channel_desc_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppCreateChannel failed, acl return " << acl_ret; + return FAILED; + } + MSI_LOG_INFO << "End init dvpp process resource"; + return SUCCESS; +} + +void DvppProcess::DestroyResource() { + if (dvpp_channel_desc_ != nullptr) { + auto acl_ret = acldvppDestroyChannel(dvpp_channel_desc_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppDestroyChannel failed, acl return " << acl_ret; + } + acl_ret = acldvppDestroyChannelDesc(dvpp_channel_desc_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppDestroyChannelDesc failed, acl return " << acl_ret; + } + dvpp_channel_desc_ = nullptr; + } +} + +void DvppProcess::Finalize() { + DestroyDecodeDesc(); + DestroyVpcOutputDesc(); + DestroyResource(); + if (resize_config_ != nullptr) { + acldvppDestroyResizeConfig(resize_config_); + resize_config_ = nullptr; + } + if (crop_area_ != nullptr) { + acldvppDestroyRoiConfig(crop_area_); + crop_area_ = nullptr; + } + if (paste_area_ != nullptr) { + acldvppDestroyRoiConfig(paste_area_); + paste_area_ = nullptr; + } + if (input_pic_dev_buffer_ != nullptr) { + acldvppFree(input_pic_dev_buffer_); + } + input_pic_buffer_size_ = 0; + MSI_LOG_INFO << "End dvpp process finalize"; +} + +Status DvppProcess::InitJpegDecodePara(const DvppDecodePara &decode_para) { + decode_para_ = decode_para; + MSI_LOG_INFO << "Init decode para, pixel_format " << decode_para_.pixel_format; + return SUCCESS; +} + +Status DvppProcess::InitResizePara(const DvppResizePara &resize_para) { + resize_para_ = resize_para; + MSI_LOG_INFO << "Init resize para, " + << "output_width " << resize_para_.output_width << ", output_height " << resize_para_.output_height; + to_resize_flag_ = true; + to_crop_flag_ = false; + to_crop_and_paste_flag_ = false; + Status ret = InitResizeOutputDesc(); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "InitResizeOutputDesc failed"; + } + return ret; +} + +Status DvppProcess::InitCommonCropPara(DvppCropInfo &crop_info, uint32_t output_width, uint32_t output_height) { + if (crop_info.crop_type == kDvppCropTypeOffset) { + if (CheckAndAdjustRoiArea(crop_info.crop_area) != SUCCESS) { + MSI_LOG_ERROR << "Check and adjust crop area failed"; + return FAILED; + } + MSI_LOG_INFO << "Init common crop para, crop type offset " + << ", left " << crop_info.crop_area.left << ", right " << crop_info.crop_area.right << ", top " + << crop_info.crop_area.top << ", bottom " << crop_info.crop_area.bottom << ", output_width " + << output_width << ", output_height " << output_height; + } else { + crop_info.crop_width = ToEven(crop_info.crop_width); + crop_info.crop_height = ToEven(crop_info.crop_height); + if (CheckRoiAreaWidthHeight(crop_info.crop_width, crop_info.crop_height) != SUCCESS) { + MSI_LOG_ERROR << "Check crop area width and height failed, actually width " << crop_info.crop_width << " height " + << crop_info.crop_height; + return FAILED; + } + MSI_LOG_INFO << "Init common crop para, crop type centre " + << ", crop_width " << crop_info.crop_width << ", crop_height " << crop_info.crop_height + << ", output_width " << output_width << ", output_height " << output_height; + } + return SUCCESS; +} + +Status DvppProcess::InitCropPara(const DvppCropPara &crop_para) { + crop_para_ = crop_para; + if (InitCommonCropPara(crop_para_.crop_info, crop_para_.output_width, crop_para_.output_height) != SUCCESS) { + MSI_LOG_ERROR << "Init common crop para failed in InitCropPara"; + return FAILED; + } + to_crop_flag_ = true; + to_resize_flag_ = false; + to_crop_and_paste_flag_ = false; + Status ret = InitCropOutputDesc(); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "InitCropOutputDesc failed"; + } + return ret; +} + +Status DvppProcess::InitCropAndPastePara(const DvppCropAndPastePara &crop_and_paste_para) { + crop_and_paste_para_ = crop_and_paste_para; + if (InitCommonCropPara(crop_and_paste_para_.crop_info, crop_and_paste_para_.output_width, + crop_and_paste_para_.output_height) != SUCCESS) { + MSI_LOG_ERROR << "Init common crop para failed in InitCropAndPastePara"; + return FAILED; + } + auto &paste_area = crop_and_paste_para_.paste_area; + if (CheckAndAdjustRoiArea(paste_area) != SUCCESS) { + MSI_LOG_ERROR << "Check and adjust paste area failed"; + return FAILED; + } + MSI_LOG_INFO << "Init crop and paste para, paste info: " + << ", left " << paste_area.left << ", right " << paste_area.right << ", top " << paste_area.top + << ", bottom " << paste_area.bottom; + + to_crop_and_paste_flag_ = true; + to_crop_flag_ = false; + to_resize_flag_ = false; + Status ret = InitCropAndPasteOutputDesc(); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "InitCropAndPasteOutputDesc failed"; + } + return ret; +} + +Status DvppProcess::InputInputBuffer(const void *pic_buffer, size_t pic_buffer_size) { + aclError acl_ret; + if (pic_buffer_size != input_pic_buffer_size_) { + acldvppFree(input_pic_dev_buffer_); + input_pic_buffer_size_ = 0; + acl_ret = acldvppMalloc(&input_pic_dev_buffer_, pic_buffer_size); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppMalloc input picture buffer on device failed, buffer size " << pic_buffer_size; + return FAILED; + } + input_pic_buffer_size_ = pic_buffer_size; + } + acl_ret = + aclrtMemcpy(input_pic_dev_buffer_, input_pic_buffer_size_, pic_buffer, pic_buffer_size, ACL_MEMCPY_HOST_TO_DEVICE); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "aclrtMemcpy input picture buffer to device, buffer size " << pic_buffer_size; + return FAILED; + } + return SUCCESS; +} + +static void JpegErrorExitCustom(j_common_ptr cinfo) { + char jpeg_last_error_msg[JMSG_LENGTH_MAX]; + if (cinfo != nullptr && cinfo->err != nullptr && cinfo->err->format_message != nullptr) { + (*(cinfo->err->format_message))(cinfo, jpeg_last_error_msg); + } + throw std::runtime_error(jpeg_last_error_msg); +} + +Status DvppProcess::GetJpegWidthHeight(const void *pic_buffer, size_t pic_buffer_size, uint32_t &image_width, + uint32_t &image_height) { + struct jpeg_decompress_struct jpeg_header; + struct jpeg_error_mgr jpeg_error; + jpeg_header.err = jpeg_std_error(&jpeg_error); + jpeg_error.error_exit = JpegErrorExitCustom; + try { + jpeg_create_decompress(&jpeg_header); + jpeg_mem_src(&jpeg_header, reinterpret_cast(pic_buffer), pic_buffer_size); + (void)jpeg_read_header(&jpeg_header, TRUE); + } catch (std::runtime_error &e) { + jpeg_destroy_decompress(&jpeg_header); + MSI_LOG_ERROR << "jpeg images read failed, " << e.what(); + return INFER_STATUS(INVALID_INPUTS) << "jpeg images decode failed"; + } + image_width = jpeg_header.image_width; + image_height = jpeg_header.image_height; + + if (jpeg_header.jpeg_color_space != JCS_YCbCr) { + MSI_LOG_ERROR << "Expect color space YUV(YCbCr), current " << jpeg_header.jpeg_color_space; + jpeg_destroy_decompress(&jpeg_header); + return INFER_STATUS(INVALID_INPUTS) << "Expect color space YUV(YCbCr), current " << jpeg_header.jpeg_color_space; + } + if (jpeg_header.dc_huff_tbl_ptrs[0] == nullptr) { + MSI_LOG_ERROR << "Only support Huffman code"; + jpeg_destroy_decompress(&jpeg_header); + return INFER_STATUS(INVALID_INPUTS) << "Only support Huffman code"; + } + jpeg_destroy_decompress(&jpeg_header); + + const uint32_t min_width = 32; + const uint32_t max_width = 8192; + const uint32_t min_height = 32; + const uint32_t max_height = 8192; + if (image_width < min_width || image_width > max_width) { + MSI_LOG_ERROR << "expect image width [" << min_width << ", " << max_width << "], the real image width is " + << image_width; + return INFER_STATUS(INVALID_INPUTS) << "expect image width [" << min_width << ", " << max_width + << "], the real image width is " << image_width; + } + if (image_height < min_height || image_height > max_height) { + MSI_LOG_ERROR << "expect image height [" << min_height << ", " << max_height << "], the real image height is " + << image_height; + return INFER_STATUS(INVALID_INPUTS) << "expect image height [" << min_height << ", " << max_height + << "], the real image height is " << image_height; + } + return SUCCESS; +} + +Status DvppProcess::Process(const void *pic_buffer, size_t pic_buffer_size, void *&output_device_buffer, + size_t &output_size) { + if (dvpp_channel_desc_ == nullptr) { + MSI_LOG_ERROR << "Process failed, dvpp not inited"; + return FAILED; + } + uint32_t image_width = 0; + uint32_t image_height = 0; + Status ret = GetJpegWidthHeight(pic_buffer, pic_buffer_size, image_width, image_height); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Get jpeg image height and width failed"; + return ret; + } + MSI_LOG_INFO << "Get jpeg width " << image_width << ", height " << image_height; + ret = InitDecodeOutputDesc(image_width, image_height); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "InitDecodeOutputDesc failed"; + return FAILED; + } + ret = UpdateCropArea(image_width, image_height); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Update crop area failed"; + return ret; + } + ret = CheckResizeImageInfo(image_width, image_height); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Check resize para failed"; + return ret; + } + if (InputInputBuffer(pic_buffer, pic_buffer_size) != SUCCESS) { + MSI_LOG_ERROR << "InputInputBuffer failed"; + return FAILED; + } + if (ProcessDecode() != SUCCESS) { + MSI_LOG_ERROR << "Process Decode failed"; + return INFER_STATUS(INVALID_INPUTS) << "Decode image failed"; + } + MSI_LOG_INFO << "Process Decode success"; + if (to_resize_flag_) { + if (ProcessResize() != SUCCESS) { + MSI_LOG_ERROR << "Process Resize failed"; + return INFER_STATUS(FAILED) << "Resize image failed"; + } + MSI_LOG_INFO << "Process Resize success"; + } else if (to_crop_flag_) { + if (ProcessCrop() != SUCCESS) { + MSI_LOG_ERROR << "Process Crop failed"; + return INFER_STATUS(FAILED) << "Crop image failed"; + } + MSI_LOG_INFO << "Process Crop success"; + } else if (to_crop_and_paste_flag_) { + if (ProcessCropAndPaste() != SUCCESS) { + MSI_LOG_ERROR << "Process Crop And Paste failed"; + return INFER_STATUS(FAILED) << "Crop And Paste image failed"; + } + MSI_LOG_INFO << "Process Crop And Paste success"; + } + if (vpc_output_buffer_dev_ == nullptr) { + output_device_buffer = decode_output_buffer_dev_; + output_size = decode_output_buffer_size_; + } else { + output_device_buffer = vpc_output_buffer_dev_; + output_size = vpc_output_buffer_size_; + } + MSI_LOG_INFO << "Process dvpp success"; + return SUCCESS; +} + +Status DvppProcess::Process(const std::vector &pic_buffer_list, + const std::vector &pic_buffer_size_list, void *&output_device_buffer, + size_t &output_size) { + auto batch_size = pic_buffer_list.size(); + if (batch_size == 0 || batch_size != pic_buffer_size_list.size()) { + MSI_LOG_ERROR << "invalid batch size " << batch_size << ", pic size count" << pic_buffer_size_list.size(); + return FAILED; + } + MSI_LOG_INFO << "Begin dvpp process, batch size " << batch_size; + if (batch_size == 1) { + return Process(pic_buffer_list[0], pic_buffer_size_list[0], output_device_buffer, output_size); + } + size_t total_buffer_size = vpc_output_buffer_size_ * batch_size; + if (batch_size_ != batch_size) { + if (batch_vpc_output_buffer_dev_ != nullptr) { + acldvppFree(batch_vpc_output_buffer_dev_); + batch_vpc_output_buffer_dev_ = nullptr; + } + batch_size_ = batch_size; + auto acl_rt = acldvppMalloc(&batch_vpc_output_buffer_dev_, total_buffer_size); + if (acl_rt != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppMalloc failed, buffer size " << total_buffer_size; + return FAILED; + } + } + for (size_t i = 0; i < batch_size; i++) { + const void *pic_buffer = pic_buffer_list[i]; + uint32_t pic_size = pic_buffer_size_list[i]; + if (pic_buffer == nullptr || pic_size == 0) { + MSI_LOG_ERROR << "Get " << 0 << "th images failed"; + return FAILED; + } + void *output_dev_buffer_tmp = nullptr; + size_t output_buffer_size_tmp = 0; + Status ret = Process(pic_buffer, pic_size, output_dev_buffer_tmp, output_buffer_size_tmp); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "dvpp process failed"; + return ret; + } + aclrtMemcpy(static_cast(batch_vpc_output_buffer_dev_) + vpc_output_buffer_size_ * i, + total_buffer_size - vpc_output_buffer_size_ * i, output_dev_buffer_tmp, vpc_output_buffer_size_, + ACL_MEMCPY_DEVICE_TO_DEVICE); + + MSI_LOG_INFO << "Dvpp process " << i << " th images success, input pic size " << pic_size << " output buffer size " + << output_buffer_size_tmp; + } + output_device_buffer = batch_vpc_output_buffer_dev_; + output_size = total_buffer_size; + MSI_LOG_INFO << "End dvpp process, batch size " << batch_size << ", output size " << output_size; + return SUCCESS; +} + +uint32_t DvppProcess::AlignmentHelper(uint32_t org_size, uint32_t alignment) const { + if (alignment == 0) { + return 0; + } + return (org_size + alignment - 1) / alignment * alignment; +} + +uint32_t DvppProcess::GetImageBufferSize(uint32_t stride_width, uint32_t stride_height, + acldvppPixelFormat pixel_format) const { + if (stride_height == 0 || stride_width == 0) { + MSI_LOG_ERROR << "invalid stride height or width, stride_width " << stride_width << " stride_height " + << stride_height; + return 0; + } + if (UINT32_MAX / 3 < stride_height || UINT32_MAX / (3 * stride_height) < stride_width) { + MSI_LOG_ERROR << "invalid stride height or width, stride_width " << stride_width << " stride_height " + << stride_height; + return 0; + } + if (pixel_format == PIXEL_FORMAT_YUV_SEMIPLANAR_420 || pixel_format == PIXEL_FORMAT_YVU_SEMIPLANAR_420) { + return stride_width * stride_height * 3 / 2; // 420 + } else if (pixel_format == PIXEL_FORMAT_YUV_SEMIPLANAR_422 || pixel_format == PIXEL_FORMAT_YVU_SEMIPLANAR_422) { + return stride_width * stride_height * 2; // 422 + } else if (pixel_format == PIXEL_FORMAT_YUV_SEMIPLANAR_444 || pixel_format == PIXEL_FORMAT_YVU_SEMIPLANAR_444) { + return stride_width * stride_height * 3; // 444 + } + MSI_LOG_ERROR << "Not support pixel format " << pixel_format; + return 0; +} + +Status DvppProcess::GetPicDescStride(uint32_t width, uint32_t height, uint32_t &stride_width, uint32_t &stride_height) { + const uint32_t width_alignment = 16; + const uint32_t height_alignment = 2; + const uint32_t stride_width_minimum = 32; + const uint32_t stride_width_maximum = 4096; + const uint32_t stride_height_minimum = 6; + const uint32_t stride_height_maximum = 4096; + + stride_width = AlignmentHelper(width, width_alignment); + stride_height = AlignmentHelper(height, height_alignment); + if (stride_width == 0 || stride_height == 0) { + MSI_LOG_ERROR << "Init VPC output desc failed, get stride width or height failed"; + return FAILED; + } + if (stride_width < stride_width_minimum || stride_width > stride_width_maximum) { + MSI_LOG_ERROR << "Expect stride width [" << stride_width_minimum << ", " << stride_width_maximum + << "], current stride width " << stride_width << " given width " << width; + return FAILED; + } + if (stride_height < stride_height_minimum || stride_height > stride_height_maximum) { + MSI_LOG_ERROR << "Expect stride height [" << stride_height_minimum << ", " << stride_height_maximum + << "], current stride height " << stride_height << " given height " << height; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::GetPicDescStrideDecode(uint32_t width, uint32_t height, uint32_t &stride_width, + uint32_t &stride_height) { + const uint32_t width_alignment = 128; + const uint32_t height_alignment = 16; + const uint32_t width_minimum = 32; + const uint32_t width_maximum = 4096; // decode support 8192, dvpp(resize/crop/crop&paste) support 4096 + const uint32_t height_minimum = 32; + const uint32_t height_maximum = 4096; // decode support 8192, dvpp(resize/crop/crop&paste) support 4096 + if (width < width_minimum || width > width_maximum) { + MSI_LOG_ERROR << "Expect width [" << width_minimum << ", " << width_maximum << "], current width " << width; + return INFER_STATUS(INVALID_INPUTS) << "Expect width [" << width_minimum << ", " << width_maximum + << "], current width " << width; + } + if (height < height_minimum || height > height_maximum) { + MSI_LOG_ERROR << "Expect height [" << height_minimum << ", " << height_maximum << "], current height " << height; + return INFER_STATUS(INVALID_INPUTS) << "Expect height [" << height_minimum << ", " << height_maximum + << "], current height " << height; + } + stride_width = AlignmentHelper(width, width_alignment); + stride_height = AlignmentHelper(height, height_alignment); + if (stride_width == 0 || stride_height == 0) { + MSI_LOG_ERROR << "Init decode output desc failed, get stride width or height failed"; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::InitVpcOutputDesc(uint32_t output_width, uint32_t output_height, acldvppPixelFormat pixel_format) { + DestroyVpcOutputDesc(); + uint32_t vpc_stride_width = 0; + uint32_t vpc_stride_height = 0; + if (GetPicDescStride(output_width, output_height, vpc_stride_width, vpc_stride_height) != SUCCESS) { + MSI_LOG_ERROR << "Init VPC output desc failed, get VPC output stride width/height failed"; + return FAILED; + } + vpc_output_buffer_size_ = GetImageBufferSize(vpc_stride_width, vpc_stride_height, pixel_format); + if (vpc_output_buffer_size_ == 0) { + MSI_LOG_ERROR << "Init VPC output desc failed, get image buffer size failed"; + return FAILED; + } + auto acl_ret = acldvppMalloc(&vpc_output_buffer_dev_, vpc_output_buffer_size_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Init VPC output desc failed, malloc dvpp memory failed"; + return FAILED; + } + vpc_output_desc_ = acldvppCreatePicDesc(); + if (vpc_output_desc_ == nullptr) { + MSI_LOG_ERROR << "Init VPC output desc failed, create pic desc failed"; + return FAILED; + } + acldvppSetPicDescData(vpc_output_desc_, vpc_output_buffer_dev_); + acldvppSetPicDescSize(vpc_output_desc_, vpc_output_buffer_size_); + acldvppSetPicDescFormat(vpc_output_desc_, pixel_format); + acldvppSetPicDescWidth(vpc_output_desc_, output_width); + acldvppSetPicDescHeight(vpc_output_desc_, output_height); + acldvppSetPicDescWidthStride(vpc_output_desc_, vpc_stride_width); + acldvppSetPicDescHeightStride(vpc_output_desc_, vpc_stride_height); + MSI_LOG_INFO << "Init VPC output desc success"; + return SUCCESS; +} + +void DvppProcess::DestroyVpcOutputDesc() { + if (vpc_output_desc_ != nullptr) { + acldvppDestroyPicDesc(vpc_output_desc_); + vpc_output_desc_ = nullptr; + } + if (vpc_output_buffer_dev_ != nullptr) { + acldvppFree(vpc_output_buffer_dev_); + vpc_output_buffer_dev_ = nullptr; + } + if (batch_vpc_output_buffer_dev_ != nullptr) { + acldvppFree(batch_vpc_output_buffer_dev_); + batch_vpc_output_buffer_dev_ = nullptr; + } + vpc_output_buffer_size_ = 0; + MSI_LOG_INFO << "End destroy vpc desc"; +} + +Status DvppProcess::InitDecodeOutputDesc(uint32_t image_width, uint32_t image_height) { + if (decode_output_buffer_dev_ != nullptr && image_width == pic_width_ && image_height == pic_height_) { + return SUCCESS; + } + DestroyDecodeDesc(); + + pic_width_ = image_width; + pic_height_ = image_height; + + uint32_t stride_width = 0; + uint32_t stride_height = 0; + Status ret = GetPicDescStrideDecode(pic_width_, pic_height_, stride_width, stride_height); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Init VPC output desc failed, get VPC output stride width/height failed"; + return ret; + } + + decode_output_buffer_size_ = GetImageBufferSize(stride_width, stride_height, decode_para_.pixel_format); + if (decode_output_buffer_size_ == 0) { + MSI_LOG_ERROR << "Init decode output desc failed, get image buffer size failed"; + return FAILED; + } + auto acl_ret = acldvppMalloc(&decode_output_buffer_dev_, decode_output_buffer_size_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Init decode output desc failed, malloc dvpp memory failed"; + return FAILED; + } + decode_output_desc_ = acldvppCreatePicDesc(); + if (decode_output_desc_ == nullptr) { + MSI_LOG_ERROR << "Init decode output desc failed, create pic desc failed"; + return FAILED; + } + acldvppSetPicDescData(decode_output_desc_, decode_output_buffer_dev_); + acldvppSetPicDescSize(decode_output_desc_, decode_output_buffer_size_); + acldvppSetPicDescFormat(decode_output_desc_, decode_para_.pixel_format); + acldvppSetPicDescWidth(decode_output_desc_, pic_width_); + acldvppSetPicDescHeight(decode_output_desc_, pic_height_); + acldvppSetPicDescWidthStride(decode_output_desc_, stride_width); + acldvppSetPicDescHeightStride(decode_output_desc_, stride_height); + MSI_LOG_INFO << "Init decode output desc success"; + return SUCCESS; +} + +Status DvppProcess::CheckRoiAreaWidthHeight(uint32_t width, uint32_t height) { + const uint32_t min_crop_width = 10; + const uint32_t max_crop_width = 4096; + const uint32_t min_crop_height = 6; + const uint32_t max_crop_height = 4096; + + if (width < min_crop_width || width > max_crop_width) { + MSI_LOG_ERROR << "Expect roi area width in [" << min_crop_width << ", " << max_crop_width << "], actually " + << width; + return FAILED; + } + if (height < min_crop_height || height > max_crop_height) { + MSI_LOG_ERROR << "Expect roi area height in [" << min_crop_height << ", " << max_crop_height << "], actually " + << height; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::CheckAndAdjustRoiArea(DvppRoiArea &area) { + if (area.right < area.left) { + MSI_LOG_ERROR << "check roi area failed, left " << area.left << ", right " << area.right; + return FAILED; + } + if (area.bottom < area.top) { + MSI_LOG_ERROR << "check roi area failed, top " << area.top << ", bottom " << area.bottom; + return FAILED; + } + + area.left = ToEven(area.left); + area.top = ToEven(area.top); + area.right = ToOdd(area.right); + area.bottom = ToOdd(area.bottom); + + auto width = area.right - area.left + 1; + auto height = area.bottom - area.top + 1; + if (CheckRoiAreaWidthHeight(width, height) != SUCCESS) { + MSI_LOG_ERROR << "Check roi area width and height failed," + << " actually width " << width << " left " << area.left << ", right " << area.right + << " actually height " << height << " top " << area.top << ", bottom " << area.bottom; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::UpdateCropArea(uint32_t image_width, uint32_t image_height) { + DvppCropInfo *crop_info = nullptr; + if (to_crop_flag_) { + crop_info = &crop_para_.crop_info; + } else if (to_crop_and_paste_flag_) { + crop_info = &crop_and_paste_para_.crop_info; + } else { + return SUCCESS; + } + if (crop_info->crop_type != kDvppCropTypeCentre) { + return SUCCESS; + } + if (image_width < crop_info->crop_width) { + MSI_LOG_ERROR << "Image width " << image_width << "smaller than crop width " << crop_info->crop_width; + return INFER_STATUS(INVALID_INPUTS) << "Image width " << image_width << "smaller than crop width " + << crop_info->crop_width; + } + if (image_height < crop_info->crop_height) { + MSI_LOG_ERROR << "Image height " << image_height << "smaller than crop height " << crop_info->crop_height; + return INFER_STATUS(INVALID_INPUTS) << "Image width " << image_width << "smaller than crop width " + << crop_info->crop_width; + } + uint32_t left = ToEven((image_width - crop_info->crop_width) / 2); + uint32_t top = ToEven((image_height - crop_info->crop_height) / 2); + uint32_t right = ToOdd(left + crop_info->crop_width); + uint32_t bottom = ToOdd(top + crop_info->crop_height); + + auto acl_ret = acldvppSetRoiConfig(crop_area_, left, right, top, bottom); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Update Crop Area failed"; + return FAILED; + } + MSI_LOG_INFO << "Update crop area, crop type centre, crop info: " + << ", left " << left << ", right " << right << ", top " << top << ", bottom " << bottom; + return SUCCESS; +} + +Status DvppProcess::CheckResizeImageInfo(uint32_t image_width, uint32_t image_height) const { + if (!to_resize_flag_) { + return SUCCESS; + } + // resize ratio required [1/32, 16] + auto check_resize_ratio = [](uint32_t before_resize, uint32_t after_resize) { + if (before_resize == 0 || after_resize == 0) { + return false; + } + if (before_resize / after_resize > 32) { + return false; + } + if (after_resize / before_resize > 16) { + return false; + } + return true; + }; + if (!check_resize_ratio(image_width, resize_para_.output_width)) { + MSI_LOG_ERROR << "Resize ratio required [1/32, 16], current width resize from " << image_width << " to " + << resize_para_.output_width; + return INFER_STATUS(INVALID_INPUTS) << "Resize ratio required [1/32, 16], current width resize from " << image_width + << " to " << resize_para_.output_width; + } + if (!check_resize_ratio(image_height, resize_para_.output_height)) { + MSI_LOG_ERROR << "Resize ratio required [1/32, 16], current height resize from " << image_height << " to " + << resize_para_.output_height; + return INFER_STATUS(INVALID_INPUTS) << "Resize ratio required [1/32, 16], current height resize from " + << image_height << " to " << resize_para_.output_height; + } + return SUCCESS; +} + +void DvppProcess::DestroyDecodeDesc() { + if (decode_output_desc_ != nullptr) { + acldvppDestroyPicDesc(decode_output_desc_); + decode_output_desc_ = nullptr; + } + if (decode_output_buffer_dev_ != nullptr) { + acldvppFree(decode_output_buffer_dev_); + decode_output_buffer_dev_ = nullptr; + } + decode_output_buffer_size_ = 0; + MSI_LOG_INFO << "End destroy decode desc"; +} + +Status DvppProcess::InitResizeOutputDesc() { + if (InitVpcOutputDesc(resize_para_.output_width, resize_para_.output_height, decode_para_.pixel_format) != SUCCESS) { + MSI_LOG_ERROR << "Init VPC output desc failed"; + return FAILED; + } + if (resize_config_ == nullptr) { + resize_config_ = acldvppCreateResizeConfig(); + if (resize_config_ == nullptr) { + MSI_LOG_ERROR << "Create Resize config failed"; + return FAILED; + } + } + return SUCCESS; +} + +Status DvppProcess::InitRoiAreaConfig(acldvppRoiConfig *&roi_area, const DvppRoiArea &init_para) { + if (roi_area == nullptr) { + roi_area = acldvppCreateRoiConfig(init_para.left, init_para.right, init_para.top, init_para.bottom); + if (roi_area == nullptr) { + MSI_LOG_ERROR << "Create Roi config failed"; + return FAILED; + } + } else { + auto acl_ret = acldvppSetRoiConfig(roi_area, init_para.left, init_para.right, init_para.top, init_para.bottom); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Set Roi config failed"; + return FAILED; + } + } + return SUCCESS; +} + +Status DvppProcess::InitCropOutputDesc() { + if (InitVpcOutputDesc(crop_para_.output_width, crop_para_.output_height, decode_para_.pixel_format) != SUCCESS) { + MSI_LOG_ERROR << "Init VPC output desc failed"; + return FAILED; + } + if (InitRoiAreaConfig(crop_area_, crop_para_.crop_info.crop_area) != SUCCESS) { + MSI_LOG_ERROR << "Init crop area failed"; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::InitCropAndPasteOutputDesc() { + if (InitVpcOutputDesc(crop_and_paste_para_.output_width, crop_and_paste_para_.output_height, + decode_para_.pixel_format) != SUCCESS) { + MSI_LOG_ERROR << "Init VPC output desc failed"; + return FAILED; + } + if (InitRoiAreaConfig(crop_area_, crop_and_paste_para_.crop_info.crop_area) != SUCCESS) { + MSI_LOG_ERROR << "Init crop area failed"; + return FAILED; + } + if (InitRoiAreaConfig(paste_area_, crop_and_paste_para_.paste_area) != SUCCESS) { + MSI_LOG_ERROR << "Init paste area failed"; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::ProcessDecode() { + aclError acl_ret; + acl_ret = acldvppJpegDecodeAsync(dvpp_channel_desc_, input_pic_dev_buffer_, input_pic_buffer_size_, + decode_output_desc_, stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppJpegDecodeAsync failed, acl return " << acl_ret; + return FAILED; + } + acl_ret = aclrtSynchronizeStream(stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "aclrtSynchronizeStream failed, acl return " << acl_ret; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::ProcessResize() { + aclError acl_ret; + acl_ret = acldvppVpcResizeAsync(dvpp_channel_desc_, decode_output_desc_, vpc_output_desc_, resize_config_, stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppVpcResizeAsync failed, acl return " << acl_ret; + return FAILED; + } + acl_ret = aclrtSynchronizeStream(stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "aclrtSynchronizeStream failed, acl return " << acl_ret; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::ProcessCrop() { + aclError acl_ret; + acl_ret = acldvppVpcCropAsync(dvpp_channel_desc_, decode_output_desc_, vpc_output_desc_, crop_area_, stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppVpcCropAsync failed, acl return " << acl_ret; + return FAILED; + } + acl_ret = aclrtSynchronizeStream(stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "aclrtSynchronizeStream failed, acl return " << acl_ret; + return FAILED; + } + return SUCCESS; +} + +Status DvppProcess::ProcessCropAndPaste() { + aclError acl_ret; + acl_ret = acldvppVpcCropAndPasteAsync(dvpp_channel_desc_, decode_output_desc_, vpc_output_desc_, crop_area_, + paste_area_, stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "acldvppVpcCropAndPasteAsync failed, acl return " << acl_ret; + return FAILED; + } + acl_ret = aclrtSynchronizeStream(stream_); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "aclrtSynchronizeStream failed, acl return " << acl_ret; + return FAILED; + } + return SUCCESS; +} + +Status DvppJsonConfigParser::GetStringValue(const nlohmann::json &json_item, const std::string &key, std::string &val) { + auto it = json_item.find(key); + if (it == json_item.end()) { + MSI_LOG_ERROR << "get string item " << key << " failed"; + return FAILED; + } + if (!it->is_string()) { + MSI_LOG_ERROR << "item " << key << " value is not string type"; + return FAILED; + } + val = it->get(); + return SUCCESS; +} + +Status DvppJsonConfigParser::GetIntValue(const nlohmann::json &json_item, const std::string &key, uint32_t &val) { + auto it = json_item.find(key); + if (it == json_item.end()) { + MSI_LOG_ERROR << "get string item " << key << " failed"; + return FAILED; + } + if (!it->is_number_integer()) { + MSI_LOG_ERROR << "item " << key << " value is not integer type"; + return FAILED; + } + val = it->get(); + return SUCCESS; +} + +Status DvppJsonConfigParser::ParseInputPara(const nlohmann::json &preprocess_item) { + auto input = preprocess_item.find("input"); + if (input == preprocess_item.end()) { + MSI_LOG_ERROR << "get input failed"; + return FAILED; + } + if (!input->is_object()) { + MSI_LOG_ERROR << "input is not object"; + return FAILED; + } + return SUCCESS; +} + +Status DvppJsonConfigParser::ParseDecodePara(const nlohmann::json &preprocess_item) { + auto decode_para = preprocess_item.find("decode_para"); + if (decode_para == preprocess_item.end()) { + MSI_LOG_ERROR << "get input failed"; + return FAILED; + } + if (!decode_para->is_object()) { + MSI_LOG_ERROR << "input is not object"; + return FAILED; + } + const std::unordered_map pixel_format_map = { + {"YUV420SP", PIXEL_FORMAT_YUV_SEMIPLANAR_420}, {"YVU420SP", PIXEL_FORMAT_YVU_SEMIPLANAR_420}, + {"YUV422SP", PIXEL_FORMAT_YUV_SEMIPLANAR_422}, {"YVU422SP", PIXEL_FORMAT_YVU_SEMIPLANAR_422}, + {"YUV444SP", PIXEL_FORMAT_YUV_SEMIPLANAR_444}, {"YVU444SP", PIXEL_FORMAT_YVU_SEMIPLANAR_444}, + }; + std::string pixel_format; + if (GetStringValue(*decode_para, "out_pixel_format", pixel_format) != SUCCESS) { + MSI_LOG_ERROR << "get op out_pixel_format failed"; + return FAILED; + } + auto format = pixel_format_map.find(pixel_format); + if (format == pixel_format_map.end()) { + MSI_LOG_ERROR << "unsupported out_pixel_format " << pixel_format; + return FAILED; + } + decode_para_.pixel_format = format->second; + return SUCCESS; +} + +Status DvppJsonConfigParser::ParseResizePara(const nlohmann::json &json_item) { + if (GetIntValue(json_item, "out_width", resize_para_.output_width) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "out_height", resize_para_.output_height) != SUCCESS) { + return FAILED; + } + resize_flag_ = true; + return SUCCESS; +} + +Status DvppJsonConfigParser::ParseCropPara(const nlohmann::json &json_item) { + if (GetIntValue(json_item, "out_width", crop_para_.output_width) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "out_height", crop_para_.output_height) != SUCCESS) { + return FAILED; + } + auto &crop_info = crop_para_.crop_info; + std::string crop_type = "crop_type"; + if (GetStringValue(json_item, "crop_type", crop_type) != SUCCESS) { + return FAILED; + } + if (crop_type == "offset") { + MSI_LOG_INFO << "Crop type is 'offset'"; + crop_info.crop_type = kDvppCropTypeOffset; + auto &crop_area = crop_info.crop_area; + if (GetIntValue(json_item, "crop_left", crop_area.left) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_top", crop_area.top) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_right", crop_area.right) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_bottom", crop_area.bottom) != SUCCESS) { + return FAILED; + } + } else if (crop_type == "centre") { + MSI_LOG_INFO << "Crop type is 'centre'"; + if (GetIntValue(json_item, "crop_width", crop_info.crop_width) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_height", crop_info.crop_height) != SUCCESS) { + return FAILED; + } + crop_info.crop_type = kDvppCropTypeCentre; + } else { + MSI_LOG_ERROR << "Invalid crop type " << crop_type << ", expect offset or centre"; + return FAILED; + } + crop_flag_ = true; + return SUCCESS; +} + +Status DvppJsonConfigParser::ParseCropAndPastePara(const nlohmann::json &json_item) { + // crop info + if (GetIntValue(json_item, "out_width", crop_and_paste_para_.output_width) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "out_height", crop_and_paste_para_.output_height) != SUCCESS) { + return FAILED; + } + auto &crop_info = crop_and_paste_para_.crop_info; + std::string crop_type = "crop_type"; + if (GetStringValue(json_item, "crop_type", crop_type) != SUCCESS) { + return FAILED; + } + if (crop_type == "offset") { + MSI_LOG_INFO << "Crop type is 'offset'"; + crop_info.crop_type = kDvppCropTypeOffset; + auto &crop_area = crop_info.crop_area; + if (GetIntValue(json_item, "crop_left", crop_area.left) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_top", crop_area.top) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_right", crop_area.right) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_bottom", crop_area.bottom) != SUCCESS) { + return FAILED; + } + } else if (crop_type == "centre") { + MSI_LOG_INFO << "Crop type is 'centre'"; + if (GetIntValue(json_item, "crop_width", crop_info.crop_width) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "crop_height", crop_info.crop_height) != SUCCESS) { + return FAILED; + } + crop_info.crop_type = kDvppCropTypeCentre; + } else { + MSI_LOG_ERROR << "Invalid crop type " << crop_type << ", expect offset or centre"; + return FAILED; + } + // paste info + auto &paste_area = crop_and_paste_para_.paste_area; + if (GetIntValue(json_item, "paste_left", paste_area.left) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "paste_top", paste_area.top) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "paste_right", paste_area.right) != SUCCESS) { + return FAILED; + } + if (GetIntValue(json_item, "paste_bottom", paste_area.bottom) != SUCCESS) { + return FAILED; + } + crop_and_paste_flag_ = true; + return SUCCESS; +} + +Status DvppJsonConfigParser::InitWithJsonConfigImp(const std::string &json_config) { + std::ifstream fp(json_config); + if (!fp.is_open()) { + MSI_LOG_ERROR << "read json config file failed"; + return FAILED; + } + const auto &model_info = nlohmann::json::parse(fp); + auto preprocess_list = model_info.find("preprocess"); + if (preprocess_list == model_info.end()) { + MSI_LOG_ERROR << "get preprocess failed"; + return FAILED; + } + if (!preprocess_list->is_array()) { + MSI_LOG_ERROR << "preprocess is not array"; + return FAILED; + } + if (preprocess_list->empty()) { + MSI_LOG_ERROR << "preprocess size is 0"; + return FAILED; + } + auto &preprocess = preprocess_list->at(0); + // input + if (ParseInputPara(preprocess) != SUCCESS) { + MSI_LOG_ERROR << "parse input failed"; + return FAILED; + } + // decode para + if (ParseDecodePara(preprocess) != SUCCESS) { + MSI_LOG_ERROR << "parse decode failed"; + return FAILED; + } + // ops + auto dvpp_process = preprocess.find("dvpp_process"); + if (dvpp_process == preprocess.end()) { + MSI_LOG_ERROR << "get dvpp_process failed"; + return FAILED; + } + if (!dvpp_process->is_object()) { + MSI_LOG_ERROR << "dvpp_process is not array"; + return FAILED; + } + const auto &item = *dvpp_process; + std::string op_name; + if (GetStringValue(item, "op_name", op_name) != SUCCESS) { + return FAILED; + } + if (op_name == "resize") { + if (ParseResizePara(item) != SUCCESS) { + MSI_LOG_ERROR << "Parse resize para failed"; + return FAILED; + } + } else if (op_name == "crop") { + if (ParseCropPara(item) != SUCCESS) { + MSI_LOG_ERROR << "Parse crop para failed"; + return FAILED; + } + } else if (op_name == "crop_and_paste") { + if (ParseCropAndPastePara(item) != SUCCESS) { + MSI_LOG_ERROR << "Parse decode para failed"; + return FAILED; + } + } else { + MSI_LOG_ERROR << "Unsupport op name " << op_name << ", expect resize, crop or crop_and_paste"; + return FAILED; + } + return SUCCESS; +} + +Status DvppJsonConfigParser::InitWithJsonConfig(const std::string &json_config) { + try { + auto ret = InitWithJsonConfigImp(json_config); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "init dvpp with json config failed, json config " << json_config; + return FAILED; + } + } catch (nlohmann::json::exception &e) { + MSI_LOG_ERROR << "init dvpp with json config failed, json config " << json_config << ", error: " << e.what(); + return FAILED; + } + MSI_LOG_INFO << "Init with json config " << json_config << " success"; + return SUCCESS; +} + +Status DvppProcess::InitWithJsonConfig(const std::string &json_config) { + DvppJsonConfigParser parser; + if (parser.InitWithJsonConfig(json_config) != SUCCESS) { + MSI_LOG_ERROR << "init json config failed"; + return FAILED; + } + if (InitJpegDecodePara(parser.GetDecodePara()) != SUCCESS) { + MSI_LOG_ERROR << "init decode para failed"; + return FAILED; + } + if (parser.HasResizeConfig()) { + if (InitResizePara(parser.GetResizePara()) != SUCCESS) { + MSI_LOG_ERROR << "init resize para failed"; + return FAILED; + } + } else if (parser.HasCropConfig()) { + if (InitCropPara(parser.GetCropPara()) != SUCCESS) { + MSI_LOG_ERROR << "init crop para failed"; + return FAILED; + } + } else if (parser.HasCropAndPasteConfig()) { + if (InitCropAndPastePara(parser.GetCropAndPastePara()) != SUCCESS) { + MSI_LOG_ERROR << "init crop and paste para failed"; + return FAILED; + } + } + return SUCCESS; +} + +} // namespace inference +} // namespace mindspore diff --git a/serving/acl/dvpp_process.h b/serving/acl/dvpp_process.h new file mode 100644 index 0000000000000000000000000000000000000000..da0275118d8ab6f64f2fee74fddf68c795f5a169 --- /dev/null +++ b/serving/acl/dvpp_process.h @@ -0,0 +1,159 @@ +/** + * Copyright 2020 Huawei Technologies 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 INC_DVPP_PROCESS_ACL +#define INC_DVPP_PROCESS_ACL +#include +#include +#include "acl/acl.h" +#include "acl/acl_mdl.h" +#include "acl/acl_rt.h" +#include "acl/ops/acl_dvpp.h" +#include "include/inference.h" + +namespace mindspore::inference { + +struct DvppDecodePara { + acldvppPixelFormat pixel_format = PIXEL_FORMAT_YUV_SEMIPLANAR_420; +}; + +struct DvppResizePara { + uint32_t output_width = 0; + uint32_t output_height = 0; +}; + +enum DvppCropType { + // crop left,top,right,bottom is given in config + kDvppCropTypeOffset = 0, + // crop left,top,right,bottom is calculated by image width/height and output crop width/height + kDvppCropTypeCentre = 1, +}; + +struct DvppRoiArea { + uint32_t left = 0; + uint32_t top = 0; + uint32_t right = 0; + uint32_t bottom = 0; +}; + +struct DvppCropInfo { + DvppCropType crop_type = kDvppCropTypeOffset; + DvppRoiArea crop_area; // when kDvppCropTypeOffset + uint32_t crop_width = 0; // when kDvppCropTypeCentre + uint32_t crop_height = 0; // when kDvppCropTypeCentre +}; + +struct DvppCropPara { + DvppCropInfo crop_info; + uint32_t output_width = 0; + uint32_t output_height = 0; +}; + +struct DvppCropAndPastePara { + DvppCropInfo crop_info; + DvppRoiArea paste_area; + uint32_t output_width = 0; + uint32_t output_height = 0; +}; + +class DvppProcess { + public: + DvppProcess(); + ~DvppProcess(); + + Status InitResource(aclrtStream stream); + void Finalize(); + Status InitJpegDecodePara(const DvppDecodePara &decode_para); // jpeg decode + (resize | crop) + Status InitResizePara(const DvppResizePara &resize_para); // jpeg decode + resize + Status InitCropPara(const DvppCropPara &crop_para); // jpeg decode + crop + Status InitCropAndPastePara(const DvppCropAndPastePara &crop_and_paste_para); // jpeg decode + crop&paste + + Status InitWithJsonConfig(const std::string &json_config); + + // output device buffer will be destroy by DvppProcess itself. + Status Process(const void *pic_buffer, size_t pic_buffer_size, void *&output_device_buffer, size_t &output_size); + Status Process(const std::vector &pic_buffer_list, const std::vector &pic_buffer_size_list, + void *&output_device_buffer, size_t &output_size); + + private: + uint32_t pic_width_ = 0; + uint32_t pic_height_ = 0; + + DvppDecodePara decode_para_; + DvppResizePara resize_para_; + DvppCropPara crop_para_; + DvppCropAndPastePara crop_and_paste_para_; + // only one of the resize or crop flag can be true + bool to_resize_flag_ = false; + bool to_crop_flag_ = false; + bool to_crop_and_paste_flag_ = false; + + void *input_pic_dev_buffer_ = nullptr; + uint32_t input_pic_buffer_size_ = 0; + + uint32_t decode_output_buffer_size_ = 0; + void *decode_output_buffer_dev_ = nullptr; + acldvppPicDesc *decode_output_desc_ = nullptr; + + acldvppResizeConfig *resize_config_ = nullptr; + acldvppRoiConfig *crop_area_ = nullptr; + acldvppRoiConfig *paste_area_ = nullptr; + + acldvppPicDesc *vpc_output_desc_ = nullptr; + void *vpc_output_buffer_dev_ = nullptr; // vpc_output_buffer_size_ length + uint32_t vpc_output_buffer_size_ = 0; + + void *batch_vpc_output_buffer_dev_ = nullptr; // batch_size_ * vpc_output_buffer_size_ length + uint32_t batch_size_ = 0; + + aclrtStream stream_ = nullptr; + acldvppChannelDesc *dvpp_channel_desc_ = nullptr; + + uint32_t AlignmentHelper(uint32_t org_size, uint32_t alignment) const; + uint32_t GetImageBufferSize(uint32_t stride_width, uint32_t stride_height, acldvppPixelFormat pixel_format) const; + Status GetPicDescStride(uint32_t width, uint32_t height, uint32_t &stride_width, uint32_t &stride_height); + Status GetPicDescStrideDecode(uint32_t width, uint32_t height, uint32_t &stride_width, uint32_t &stride_height); + Status InputInputBuffer(const void *pic_buffer, size_t pic_buffer_size); + Status InitDecodeOutputDesc(uint32_t image_width, + uint32_t image_height); // decode_output_desc_, decode_output_buffer_dev_ + Status CheckRoiAreaWidthHeight(uint32_t width, uint32_t height); + Status CheckAndAdjustRoiArea(DvppRoiArea &area); + Status UpdateCropArea(uint32_t image_width, uint32_t image_height); + Status CheckResizeImageInfo(uint32_t image_width, uint32_t image_height) const; + void DestroyDecodeDesc(); + + Status InitVpcOutputDesc(uint32_t output_width, uint32_t output_height, + acldvppPixelFormat pixel_format); // vpc_output_desc_, vpc_output_buffer_dev_batch_ + Status InitRoiAreaConfig(acldvppRoiConfig *&roi_area, const DvppRoiArea &init_para); + Status InitCommonCropPara(DvppCropInfo &crop_info, uint32_t out_width, uint32_t out_height); + Status InitResizeOutputDesc(); // vpc_output_desc_, vpc_output_buffer_dev_, resize_config + Status InitCropOutputDesc(); // vpc_output_desc_, vpc_output_buffer_dev_, crop_area_ + Status InitCropAndPasteOutputDesc(); // vpc_output_desc_, vpc_output_buffer_dev_, crop_area_, paste_area_ + void DestroyVpcOutputDesc(); + + Status ProcessDecode(); + Status ProcessResize(); + Status ProcessCrop(); + Status ProcessCropAndPaste(); + void DestroyResource(); + + Status GetJpegWidthHeight(const void *pic_buffer, size_t pic_buffer_size, uint32_t &image_width, + uint32_t &image_height); +}; + +} // namespace mindspore::inference + +#endif // INC_DVPP_PROCESS_ACL diff --git a/serving/acl/model_info_example.json b/serving/acl/model_info_example.json new file mode 100644 index 0000000000000000000000000000000000000000..e6d37048d046b69dcc96cc387815ac2e47ffbb87 --- /dev/null +++ b/serving/acl/model_info_example.json @@ -0,0 +1,68 @@ +{ + "preprocess": [ + { + "input": { + "index": 0 + }, + "decode_para": { + "out_pixel_format": "YUV420SP" + }, + "dvpp_process": { + "op_name": "resize", + "out_width": 224, + "out_height": 224 + }, + "sample of dvpp_process content": [ + { + "op_name": "resize", + "out_width": 224, + "out_height": 224 + }, + { + "op_name": "crop", + "crop_type": "offset", + "crop_left": 10, + "crop_top": 10, + "crop_right": 100, + "crop_bottom": 200, + "out_width": 224, + "out_height": 224 + }, + { + "op_name": "crop", + "crop_type": "centre", + "crop_width": 100, + "crop_height": 100, + "out_width": 224, + "out_height": 224 + }, + { + "op_name": "crop_and_paste", + "crop_type": "offset", + "crop_left": 10, + "crop_top": 10, + "crop_right": 100, + "crop_bottom": 200, + "paste_left": 10, + "paste_top": 10, + "paste_right": 100, + "paste_bottom": 200, + "out_width": 224, + "out_height": 224 + }, + { + "op_name": "crop_and_paste", + "crop_type": "centre", + "crop_width": 100, + "crop_height": 100, + "paste_left": 10, + "paste_top": 10, + "paste_right": 100, + "paste_bottom": 200, + "out_width": 224, + "out_height": 224 + } + ] + } + ] +} \ No newline at end of file diff --git a/serving/acl/model_process.cc b/serving/acl/model_process.cc index a76539e72fa1ab7d43994b53a5d693ce9810f38c..4016d1c00b278825cb0df8f43d4d1c713eac83da 100644 --- a/serving/acl/model_process.cc +++ b/serving/acl/model_process.cc @@ -23,41 +23,44 @@ namespace mindspore { namespace inference { -bool ModelProcess::LoadModelFromFile(const std::string &file_name, uint32_t &model_id) { - aclError acl_ret = aclmdlLoadFromFile(file_name.c_str(), &model_id); - if (acl_ret != ACL_ERROR_NONE) { - MSI_LOG_ERROR << "Read model file failed, file name is " << file_name; - return false; - } - MSI_LOG_INFO << "Load model success " << file_name; - +Status ModelProcess::PreInitModelResource() { model_desc_ = aclmdlCreateDesc(); - acl_ret = aclmdlGetDesc(model_desc_, model_id); + aclError acl_ret = aclmdlGetDesc(model_desc_, model_id_); if (acl_ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Read model desc failed"; - return false; + return FAILED; } - bool ret = InitInputsBuffer(); - if (!ret) { + Status ret = InitInputsBuffer(); + if (ret != SUCCESS) { MSI_LOG_ERROR << "Create input buffer failed"; - return false; + return FAILED; } ret = InitOutputsBuffer(); - if (!ret) { + if (ret != SUCCESS) { MSI_LOG_ERROR << "Create output buffer failed"; - return false; + return FAILED; } + return SUCCESS; +} + +Status ModelProcess::LoadModelFromFile(const std::string &file_name, uint32_t &model_id) { + aclError acl_ret = aclmdlLoadFromFile(file_name.c_str(), &model_id); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Read model file failed, file name is " << file_name; + return FAILED; + } + MSI_LOG_INFO << "Load model success " << file_name; model_id_ = model_id; - return true; + if (PreInitModelResource() != SUCCESS) { + aclmdlUnload(model_id_); + MSI_LOG_ERROR << "Pre init model resource failed, file name is " << file_name; + return FAILED; + } + return SUCCESS; } -bool ModelProcess::InitInputsBuffer() { +Status ModelProcess::InitInputsBuffer() { aclError ret; - inputs_ = aclmdlCreateDataset(); - if (inputs_ == nullptr) { - MSI_LOG_ERROR << "Create input dataset failed"; - return false; - } size_t input_size = aclmdlGetNumInputs(model_desc_); for (size_t i = 0; i < input_size; ++i) { @@ -67,7 +70,7 @@ bool ModelProcess::InitInputsBuffer() { ret = aclrtMalloc(&data_mem_buffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Malloc device input buffer faild , input size " << buffer_size; - return false; + return FAILED; } } @@ -75,17 +78,20 @@ bool ModelProcess::InitInputsBuffer() { ret = aclmdlGetInputDims(model_desc_, i, &dims); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Get input shape failed"; - return false; + if (!is_run_on_device_) { + aclrtFree(data_mem_buffer); + } + return FAILED; } - aclDataType dataType = aclmdlGetInputDataType(model_desc_, i); + aclDataType data_type = aclmdlGetInputDataType(model_desc_, i); std::vector shape(dims.dims, dims.dims + dims.dimCount); - input_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, dataType, shape}); + input_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape}); } MSI_LOG_INFO << "Create model inputs success"; - return true; + return SUCCESS; } -bool ModelProcess::CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset) { +Status ModelProcess::CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset) { aclError ret; auto free_data_buffer = [this](void *dataMemBuffer) { if (!is_run_on_device_) { @@ -98,13 +104,13 @@ bool ModelProcess::CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, ret = aclrtMalloc(&data_mem_buffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Malloc device buffer faild , buffer size " << buffer_size; - return false; + return FAILED; } } else { ret = aclrtMallocHost(&data_mem_buffer, buffer_size); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Malloc device buffer faild , buffer size " << buffer_size; - return false; + return FAILED; } } @@ -112,46 +118,51 @@ bool ModelProcess::CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, if (data_buffer == nullptr) { MSI_LOG_ERROR << "Create Data Buffer failed"; free_data_buffer(data_mem_buffer); - return false; + return FAILED; } ret = aclmdlAddDatasetBuffer(dataset, data_buffer); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "add data buffer failed"; free_data_buffer(data_mem_buffer); aclDestroyDataBuffer(data_buffer); - return false; + return FAILED; } - return true; + return SUCCESS; } -bool ModelProcess::InitOutputsBuffer() { +Status ModelProcess::InitOutputsBuffer() { aclError ret; outputs_ = aclmdlCreateDataset(); if (outputs_ == nullptr) { MSI_LOG_ERROR << "Create input dataset failed"; - return false; + return FAILED; } size_t output_size = aclmdlGetNumOutputs(model_desc_); for (size_t i = 0; i < output_size; ++i) { auto buffer_size = aclmdlGetOutputSizeByIndex(model_desc_, i); void *data_mem_buffer = nullptr; - if (CreateDataBuffer(data_mem_buffer, buffer_size, outputs_) != true) { + if (CreateDataBuffer(data_mem_buffer, buffer_size, outputs_) != SUCCESS) { MSI_LOG_ERROR << "add output data buffer failed, buffer size " << buffer_size; - return false; + return FAILED; } aclmdlIODims dims; ret = aclmdlGetOutputDims(model_desc_, i, &dims); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Get input shape failed"; - return false; + if (!is_run_on_device_) { + aclrtFree(data_mem_buffer); + } else { + aclrtFreeHost(data_mem_buffer); + } + return FAILED; } - aclDataType dataType = aclmdlGetOutputDataType(model_desc_, i); + aclDataType data_type = aclmdlGetOutputDataType(model_desc_, i); std::vector shape(dims.dims, dims.dims + dims.dimCount); - output_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, dataType, shape}); + output_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape}); } MSI_LOG_INFO << "Create model output success"; - return true; + return SUCCESS; } void ModelProcess::DestroyInputsDataset() { @@ -176,27 +187,29 @@ void ModelProcess::DestroyInputsDataMem() { } void ModelProcess::DestroyInputsBuffer() { - DestroyInputsDataset(); DestroyInputsDataMem(); + DestroyInputsDataset(); } void ModelProcess::DestroyOutputsBuffer() { + for (const auto &item : output_infos_) { + if (!is_run_on_device_) { + aclrtFree(item.device_data); + } else { + aclrtFreeHost(item.device_data); + } + } + output_infos_.clear(); + if (outputs_ == nullptr) { return; } for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(outputs_); i++) { auto dataBuffer = aclmdlGetDatasetBuffer(outputs_, i); - auto data = aclGetDataBufferAddr(dataBuffer); - if (!is_run_on_device_) { - aclrtFree(data); - } else { - aclrtFreeHost(data); - } aclDestroyDataBuffer(dataBuffer); } aclmdlDestroyDataset(outputs_); outputs_ = nullptr; - output_infos_.clear(); } void ModelProcess::UnLoad() { @@ -213,24 +226,26 @@ void ModelProcess::UnLoad() { MSI_LOG_INFO << "End unload model " << model_id_; } -bool ModelProcess::CheckAndInitInput(const RequestBase &request) { +Status ModelProcess::CheckAndInitInput(const RequestBase &request) { aclError ret; inputs_ = aclmdlCreateDataset(); // check inputs if (request.size() != input_infos_.size()) { MSI_LOG_ERROR << "inputs count not match, required count " << input_infos_.size() << ", given count " << request.size(); - return false; + return INFER_STATUS(INVALID_INPUTS) << "inputs count not match, required count " << input_infos_.size() + << ", given count " << request.size(); } for (size_t i = 0; i < input_infos_.size(); i++) { if (request[i] == nullptr) { MSI_LOG_ERROR << "input " << i << " cannot be null"; - return false; + return FAILED; } if (request[i]->data_size() != input_infos_[i].buffer_size) { MSI_LOG_ERROR << "input " << i << " data size not match, required size " << input_infos_[i].buffer_size << ", given count " << request[i]->data_size(); - return false; + return INFER_STATUS(INVALID_INPUTS) << "input " << i << " data size not match, required size " + << input_infos_[i].buffer_size << ", given count " << request[i]->data_size(); } } // copy inputs @@ -242,7 +257,7 @@ bool ModelProcess::CheckAndInitInput(const RequestBase &request) { ret = aclrtMemcpy(info.device_data, info.buffer_size, data, request[i]->data_size(), ACL_MEMCPY_HOST_TO_DEVICE); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "memcpy input " << i << " data to device failed, buffer size " << request[i]->data_size(); - return false; + return FAILED; } input_buffer = info.device_data; } else { @@ -251,32 +266,70 @@ bool ModelProcess::CheckAndInitInput(const RequestBase &request) { auto data_buffer = aclCreateDataBuffer(input_buffer, info.buffer_size); if (data_buffer == nullptr) { MSI_LOG_ERROR << "Create Data Buffer failed"; - return false; + return FAILED; } ret = aclmdlAddDatasetBuffer(inputs_, data_buffer); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "add data buffer failed"; aclDestroyDataBuffer(data_buffer); - return false; + return FAILED; } } - return true; + return SUCCESS; +} + +Status ModelProcess::CheckAndInitDvppInput(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size, + size_t input_index) { + aclError ret; + inputs_ = aclmdlCreateDataset(); + // check inputs + if (input_index >= input_infos_.size()) { + MSI_LOG_ERROR << "inputs count not match, required count " << input_infos_.size() << ", given index " + << input_index; + return INFER_STATUS(INVALID_INPUTS) << "inputs count not match, required count " << input_infos_.size() + << ", given index " << input_index; + } + if (dvpp_outputs_buffer_dev == nullptr) { + MSI_LOG_ERROR << "input " << 0 << " cannot be null"; + return FAILED; + } + if (dvpp_outputs_buffer_size != input_infos_[input_index].buffer_size) { + MSI_LOG_ERROR << "input " << 0 << " data size not match, required size " << input_infos_[input_index].buffer_size + << ", given count " << dvpp_outputs_buffer_size; + return INFER_STATUS(INVALID_INPUTS) << "input " << 0 << " data size not match, required size " + << input_infos_[input_index].buffer_size << ", given count " + << dvpp_outputs_buffer_size; + } + // copy inputs + auto &info = input_infos_[input_index]; + auto data_buffer = aclCreateDataBuffer(const_cast(dvpp_outputs_buffer_dev), info.buffer_size); + if (data_buffer == nullptr) { + MSI_LOG_ERROR << "Create Data Buffer failed"; + return FAILED; + } + ret = aclmdlAddDatasetBuffer(inputs_, data_buffer); + if (ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "add data buffer failed"; + aclDestroyDataBuffer(data_buffer); + return FAILED; + } + return SUCCESS; } -bool ModelProcess::BuildOutputs(ReplyBase &reply) { +Status ModelProcess::BuildOutputs(ReplyBase &reply) { aclError ret; // copy outputs reply.clear(); - std::unordered_map dataTypeMap = { + std::unordered_map data_type_map = { {ACL_FLOAT16, inference::kMSI_Float16}, {ACL_FLOAT, inference::kMSI_Float32}, {ACL_DOUBLE, inference::kMSI_Float64}, {ACL_INT8, inference::kMSI_Int8}, {ACL_INT16, inference::kMSI_Int16}, {ACL_INT32, inference::kMSI_Int32}, {ACL_INT64, inference::kMSI_Int64}, {ACL_UINT8, inference::kMSI_Uint8}, {ACL_UINT16, inference::kMSI_Uint16}, {ACL_UINT32, inference::kMSI_Uint32}, {ACL_UINT64, inference::kMSI_Uint64}, {ACL_BOOL, inference::kMSI_Bool}, }; - auto trans_to_serving_type = [&dataTypeMap](aclDataType data_type) { - auto it = dataTypeMap.find(data_type); - if (it == dataTypeMap.end()) { + auto trans_to_serving_type = [&data_type_map](aclDataType data_type) { + auto it = data_type_map.find(data_type); + if (it == data_type_map.end()) { return inference::kMSI_Unknown; } else { return it->second; @@ -287,53 +340,93 @@ bool ModelProcess::BuildOutputs(ReplyBase &reply) { auto output = reply.add(); if (output == nullptr) { MSI_LOG_ERROR << "add new output failed"; - return false; + return FAILED; } output->set_data_type(trans_to_serving_type(info.data_type)); output->set_shape(info.dims); if (!output->resize_data(info.buffer_size)) { MSI_LOG_ERROR << "new output data buffer failed, data size " << info.buffer_size; - return false; + return FAILED; } if (!is_run_on_device_) { ret = aclrtMemcpy(output->mutable_data(), output->data_size(), info.device_data, info.buffer_size, ACL_MEMCPY_DEVICE_TO_HOST); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Memcpy output " << i << " to host failed, memory size " << info.buffer_size; - return false; + return FAILED; } } else { ret = aclrtMemcpy(output->mutable_data(), output->data_size(), info.device_data, info.buffer_size, ACL_MEMCPY_HOST_TO_HOST); if (ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Memcpy output " << i << " to host failed, memory size " << info.buffer_size; - return false; + return FAILED; } } } - return true; + return SUCCESS; +} + +Status ModelProcess::Execute(const RequestBase &request, ReplyBase &reply) { + aclError acl_ret; + Status ret = CheckAndInitInput(request); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "check or init input failed"; + DestroyInputsDataset(); + return ret; // forward status error + } + acl_ret = aclmdlExecute(model_id_, inputs_, outputs_); + DestroyInputsDataset(); + if (acl_ret != ACL_ERROR_NONE) { + MSI_LOG_ERROR << "Execute Model Failed"; + return FAILED; + } + ret = BuildOutputs(reply); + if (ret != SUCCESS) { + MSI_LOG_ERROR << "Build outputs faield"; + return FAILED; + } + MSI_LOG_INFO << "excute model success"; + return SUCCESS; } -bool ModelProcess::Execute(const RequestBase &request, ReplyBase &reply) { +Status ModelProcess::Execute(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size, ReplyBase &reply) { aclError acl_ret; - if (CheckAndInitInput(request) != true) { + if (input_infos_.size() != 1) { + MSI_LOG_ERROR << "can only support input size 1, now model inputs size is " << input_infos_.size(); + return INFER_STATUS(INVALID_INPUTS) << "can only support input size 1, now model inputs size is " + << input_infos_.size(); + } + Status ret = CheckAndInitDvppInput(dvpp_outputs_buffer_dev, dvpp_outputs_buffer_size, 0); + if (ret != SUCCESS) { MSI_LOG_ERROR << "check or init input failed"; DestroyInputsDataset(); - return false; + return ret; // forward status msg } acl_ret = aclmdlExecute(model_id_, inputs_, outputs_); DestroyInputsDataset(); if (acl_ret != ACL_ERROR_NONE) { MSI_LOG_ERROR << "Execute Model Failed"; - return false; + return INFER_STATUS(FAILED) << "Execute Model Failed"; } - bool ret = BuildOutputs(reply); - if (!ret) { + ret = BuildOutputs(reply); + if (ret != SUCCESS) { MSI_LOG_ERROR << "Build outputs faield"; - return false; + return FAILED; } MSI_LOG_INFO << "excute model success"; - return true; + return SUCCESS; +} + +size_t ModelProcess::GetBatchSize() const { + if (input_infos_.empty()) { + MSI_LOG_ERROR << "Model is not loaded"; + return 0; + } + if (input_infos_[0].dims.empty()) { + return 1; + } + return static_cast(input_infos_[0].dims[0]); } } // namespace inference diff --git a/serving/acl/model_process.h b/serving/acl/model_process.h index 61bf72574ac5484cd55dae377890efc5e7910980..ae716404ff5ed60ba42b7e521fabed5755ea4044 100644 --- a/serving/acl/model_process.h +++ b/serving/acl/model_process.h @@ -21,7 +21,6 @@ #include "acl/acl.h" #include "acl/acl_mdl.h" #include "acl/acl_rt.h" -#include "serving/core/util/status.h" #include "include/inference.h" namespace mindspore { @@ -34,21 +33,30 @@ struct AclTensorInfo { std::vector dims; }; +struct ImagesDvppOutput { + void *buffer_device = nullptr; + size_t buffer_size = 0; + size_t input_index = 0; +}; + class ModelProcess { public: ModelProcess() {} ~ModelProcess() {} - bool LoadModelFromFile(const std::string &file_name, uint32_t &model_id); + Status LoadModelFromFile(const std::string &file_name, uint32_t &model_id); void UnLoad(); // override this method to avoid request/reply data copy - bool Execute(const RequestBase &request, ReplyBase &reply); - + Status Execute(const RequestBase &request, ReplyBase &reply); + Status Execute(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size, ReplyBase &reply); void SetIsDevice(bool is_device) { is_run_on_device_ = is_device; } + size_t GetBatchSize() const; + private: uint32_t model_id_ = 0xffffffff; + // if run one device(AICPU), there is no need to alloc device memory and copy inputs to(/outputs from) device bool is_run_on_device_ = false; aclmdlDesc *model_desc_ = nullptr; aclmdlDataset *inputs_ = nullptr; @@ -56,12 +64,15 @@ class ModelProcess { std::vector input_infos_; std::vector output_infos_; - bool CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset); - bool CheckAndInitInput(const RequestBase &request); - bool BuildOutputs(ReplyBase &reply); + Status PreInitModelResource(); + Status CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset); + Status CheckAndInitInput(const RequestBase &request); + Status CheckAndInitDvppInput(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size, + size_t input_index); + Status BuildOutputs(ReplyBase &reply); - bool InitInputsBuffer(); - bool InitOutputsBuffer(); + Status InitInputsBuffer(); + Status InitOutputsBuffer(); void DestroyInputsDataset(); void DestroyInputsDataMem(); void DestroyInputsBuffer(); diff --git a/serving/core/server.cc b/serving/core/server.cc index 180e07bb0cda0cb5a381fb9927c1721a25aa00ed..61a3f1558a27ec25194a700a9772689e13ffe92a 100644 --- a/serving/core/server.cc +++ b/serving/core/server.cc @@ -31,7 +31,6 @@ #include "core/version_control/version_controller.h" #include "core/util/file_system_operation.h" #include "core/serving_tensor.h" -#include "util/status.h" using ms_serving::MSService; using ms_serving::PredictReply; @@ -45,7 +44,7 @@ namespace serving { { \ auto time_end_##name = std::chrono::steady_clock::now(); \ auto time_cost = std::chrono::duration(time_end_##name - time_start_##name).count(); \ - MSI_LOG_INFO << #name " Time Cost " << time_cost << "ms ---------------------"; \ + MSI_LOG_INFO << #name " Time Cost # " << time_cost << " ms ---------------------"; \ } Status Session::CreatDeviceSession(const std::string &device, uint32_t device_id) { @@ -75,15 +74,26 @@ Status Session::Predict(const PredictRequest &request, PredictReply &reply) { std::lock_guard lock(mutex_); MSI_LOG(INFO) << "run Predict"; - ServingRequest serving_request(request); - ServingReply serving_reply(reply); + if (request.images_size() > 0) { + ServingImagesRequest serving_images(request); + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + Status ret = session_->ExecuteModel(graph_id_, serving_images, serving_request, serving_reply); + if (ret != SUCCESS) { + MSI_LOG(ERROR) << "execute model with images return failed"; + return ret; + } + } else if (request.data_size() > 0) { + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + Status ret = session_->ExecuteModel(graph_id_, serving_request, serving_reply); + if (ret != SUCCESS) { + MSI_LOG(ERROR) << "execute model with datas return failed"; + return ret; + } + } - auto ret = session_->ExecuteModel(graph_id_, serving_request, serving_reply); MSI_LOG(INFO) << "run Predict finished"; - if (Status(ret) != SUCCESS) { - MSI_LOG(ERROR) << "execute model return failed"; - return Status(ret); - } return SUCCESS; } @@ -98,9 +108,9 @@ Status Session::Warmup(const MindSporeModelPtr model) { MSI_TIME_STAMP_START(LoadModelFromFile) auto ret = session_->LoadModelFromFile(file_name, graph_id_); MSI_TIME_STAMP_END(LoadModelFromFile) - if (Status(ret) != SUCCESS) { + if (ret != SUCCESS) { MSI_LOG(ERROR) << "Load graph model failed, file name is " << file_name.c_str(); - return Status(ret); + return ret; } model_loaded_ = true; MSI_LOG(INFO) << "Session Warmup finished"; @@ -123,14 +133,19 @@ std::promise exit_requested; void ClearEnv() { Session::Instance().Clear(); } void HandleSignal(int sig) { exit_requested.set_value(); } -grpc::Status CreatGRPCStatus(Status status) { - switch (status) { +grpc::Status CreatGRPCStatus(const Status &status) { + switch (status.StatusCode()) { case SUCCESS: return grpc::Status::OK; case FAILED: return grpc::Status::CANCELLED; - case INVALID_INPUTS: - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "The Predict Inputs do not match the Model Request!"); + case INVALID_INPUTS: { + auto status_msg = status.StatusMessage(); + if (status_msg.empty()) { + status_msg = "The Predict Inputs do not match the Model Request!"; + } + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, status_msg); + } default: return grpc::Status::CANCELLED; } diff --git a/serving/core/server.h b/serving/core/server.h index 3f8b1da06654d0c8c74c44e8f4e325667a600999..f97db84fce359288940333c0a2782c43c2a0b83d 100644 --- a/serving/core/server.h +++ b/serving/core/server.h @@ -31,6 +31,10 @@ namespace serving { using ms_serving::PredictReply; using ms_serving::PredictRequest; +using inference::Status; +using inference::SUCCESS; +using inference::FAILED; +using inference::INVALID_INPUTS; class Session { public: diff --git a/serving/core/serving_tensor.cc b/serving/core/serving_tensor.cc index 4fe43cdf4cdeed1e8b13bc982bb5fd8b30f844c9..72225f375495dd774007aa964a9f75a32c438f06 100644 --- a/serving/core/serving_tensor.cc +++ b/serving/core/serving_tensor.cc @@ -120,7 +120,7 @@ ServingRequest::ServingRequest(const ms_serving::PredictRequest &request) : requ [](const ms_serving::Tensor &item) { return ServingTensor(const_cast(item)); }); } -size_t ServingRequest::size() const { return request_.data_size(); } +size_t ServingRequest::size() const { return cache_.size(); } const InferTensorBase *ServingRequest::operator[](size_t index) const { if (index >= cache_.size()) { @@ -130,6 +130,22 @@ const InferTensorBase *ServingRequest::operator[](size_t index) const { return &(cache_[index]); } +ServingImages::ServingImages(const ms_serving::Images &images) : images_(images) {} + +size_t ServingImages::batch_size() const { return images_.images_size(); } + +bool ServingImages::get(size_t index, const void *&pic_buffer, uint32_t &pic_size) const { + if (index >= static_cast(images_.images_size())) { + MSI_LOG_ERROR << "visit invalid index " << index << " total size " << images_.images_size(); + return false; + } + pic_buffer = images_.images(index).data(); + pic_size = images_.images(index).size(); + return true; +} + +size_t ServingImages::input_index() const { return static_cast(images_.input_index()); } + size_t ServingReply::size() const { return cache_.size(); } InferTensorBase *ServingReply::operator[](size_t index) { @@ -160,5 +176,21 @@ InferTensorBase *ServingReply::add() { void ServingReply::clear() { reply_.mutable_result()->Clear(); } +ServingImagesRequest::ServingImagesRequest(const ms_serving::PredictRequest &request) : request_(request) { + auto &images_inputs = request_.images(); + std::transform(images_inputs.begin(), images_inputs.end(), std::back_inserter(cache_), + [](const ms_serving::Images &item) { return ServingImages(const_cast(item)); }); +} + +size_t ServingImagesRequest::size() const { return cache_.size(); } + +const inference::InferImagesBase *ServingImagesRequest::operator[](size_t index) const { + if (index >= cache_.size()) { + MSI_LOG_ERROR << "visit invalid index " << index << " total size " << cache_.size(); + return nullptr; + } + return &(cache_[index]); +} + } // namespace serving } // namespace mindspore diff --git a/serving/core/serving_tensor.h b/serving/core/serving_tensor.h index fbbc1e50409d5adb8592e4b2fcfb65b4fb82e60c..b55112fd64f7d689f0762a34401d94260c82b5aa 100644 --- a/serving/core/serving_tensor.h +++ b/serving/core/serving_tensor.h @@ -47,6 +47,18 @@ class MS_API ServingTensor : public inference::InferTensorBase { ms_serving::Tensor &tensor_; }; +class ServingImages : public inference::InferImagesBase { + public: + explicit ServingImages(const ms_serving::Images &images); + + size_t batch_size() const override; + bool get(size_t index, const void *&pic_buffer, uint32_t &pic_size) const override; + size_t input_index() const override; + + private: + const ms_serving::Images &images_; +}; + class ServingRequest : public inference::RequestBase { public: explicit ServingRequest(const ms_serving::PredictRequest &request); @@ -74,6 +86,18 @@ class ServingReply : public inference::ReplyBase { std::vector cache_; }; +class ServingImagesRequest : public inference::ImagesRequestBase { + public: + explicit ServingImagesRequest(const ms_serving::PredictRequest &request); + + size_t size() const override; + const inference::InferImagesBase *operator[](size_t index) const override; + + private: + const ms_serving::PredictRequest &request_; + std::vector cache_; +}; + } // namespace serving } // namespace mindspore #endif // MINDSPORE_SERVING_TENSOR_H_ diff --git a/serving/core/util/status.h b/serving/core/util/status.h index d416b8c88591afe715ea229db9fc9222098d05bc..e1f1df687497e8160dc3f026a0b84dec8fb46cc4 100644 --- a/serving/core/util/status.h +++ b/serving/core/util/status.h @@ -15,10 +15,14 @@ */ #ifndef MINDSPORE_STATUS_H #define MINDSPORE_STATUS_H +#include "include/inference.h" + namespace mindspore { namespace serving { -using Status = uint32_t; -enum ServingStatus { SUCCESS = 0, FAILED, INVALID_INPUTS }; +using inference::Status; +using inference::SUCCESS; +using inference::FAILED; +using inference::INVALID_INPUTS; } // namespace serving } // namespace mindspore diff --git a/serving/ms_service.proto b/serving/ms_service.proto index f11bc235e7c07f94df2e691007f1a0649403bb3d..26cedad91b7106475c88b955783ff47833761a05 100644 --- a/serving/ms_service.proto +++ b/serving/ms_service.proto @@ -20,17 +20,19 @@ syntax = "proto3"; package ms_serving; service MSService { - rpc Predict(PredictRequest) returns (PredictReply) {} - rpc Test(PredictRequest) returns (PredictReply) {} + rpc Predict(PredictRequest) returns (PredictReply) {} + rpc Test(PredictRequest) returns (PredictReply) {} } message PredictRequest { - repeated Tensor data = 1; + repeated Tensor data = 1; + repeated Images images = 2; } message PredictReply { - repeated Tensor result = 1; + repeated Tensor result = 1; } + enum DataType { MS_UNKNOWN = 0; MS_BOOL = 1; @@ -62,3 +64,7 @@ message Tensor { bytes data = 3; } +message Images{ + repeated bytes images = 1; + uint32 input_index = 2; +} diff --git a/tests/ut/cpp/CMakeLists.txt b/tests/ut/cpp/CMakeLists.txt index 3cb637b98224bbea819f1d235831c48d3b14487e..eddf8f66ba12b4731eb2f0bb559cdacf23fed756 100644 --- a/tests/ut/cpp/CMakeLists.txt +++ b/tests/ut/cpp/CMakeLists.txt @@ -51,6 +51,10 @@ else() endif() endforeach () endif() +# removing serving ut +file(GLOB_RECURSE SERVING_ACL_UT_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} serving/*.cc) +list(REMOVE_ITEM UT_SRCS ${SERVING_ACL_UT_SRCS}) +add_subdirectory(serving) file(GLOB_RECURSE MINDSPORE_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "../../../mindspore/core/base/*.cc" @@ -163,7 +167,7 @@ file(GLOB_RECURSE UT_SUTB_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "stub/ge/*.cc" ) -add_executable(ut_tests ${UT_SRCS} ${MINDSPORE_SRC_LIST} ${UT_SUTB_SRC_LIST}) +add_executable(ut_tests ${UT_SRCS} ${MINDSPORE_SRC_LIST} ${UT_SUTB_SRC_LIST} $) if (ENABLE_GE) if(ENABLE_TRAIN) @@ -188,3 +192,14 @@ if (USE_GLOG) endif() target_link_libraries(ut_tests PRIVATE securec graph) + +# link grpc +if (EXISTS ${grpc_ROOT}/lib64) + set(gRPC_DIR "${grpc_ROOT}/lib64/cmake/grpc") +else () + set(gRPC_DIR "${grpc_ROOT}/lib/cmake/grpc") +endif () +find_package(gRPC CONFIG REQUIRED) +target_link_libraries(ut_tests PRIVATE gRPC::grpc++) +target_link_libraries(ut_tests PRIVATE gRPC::grpc++_reflection) +target_link_libraries(ut_tests PRIVATE protobuf::libprotobuf) \ No newline at end of file diff --git a/tests/ut/cpp/serving/CMakeLists.txt b/tests/ut/cpp/serving/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..42c682e00214395cc4c042017998b696ff0fb6e6 --- /dev/null +++ b/tests/ut/cpp/serving/CMakeLists.txt @@ -0,0 +1,90 @@ +find_package(Threads REQUIRED) + +# This branch assumes that gRPC and all its dependencies are already installed +# on this system, so they can be located by find_package(). + +# Find Protobuf installation +# Looks for protobuf-config.cmake file installed by Protobuf's cmake installation. + +#set(protobuf_MODULE_COMPATIBLE TRUE) +#find_package(Protobuf CONFIG REQUIRED) +#message(STATUS "Using protobuf ${protobuf_VERSION}") +add_library(protobuf::libprotobuf ALIAS protobuf::protobuf) +add_executable(protobuf::libprotoc ALIAS protobuf::protoc) + +set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) +if (CMAKE_CROSSCOMPILING) + find_program(_PROTOBUF_PROTOC protoc) +else () + set(_PROTOBUF_PROTOC $) +endif () + +# Find gRPC installation +# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. +if (EXISTS ${grpc_ROOT}/lib64) + set(gRPC_DIR "${grpc_ROOT}/lib64/cmake/grpc") +else () + set(gRPC_DIR "${grpc_ROOT}/lib/cmake/grpc") +endif () +message("serving ut using grpc_DIR : " ${gPRC_DIR}) + +find_package(gRPC CONFIG REQUIRED) +message(STATUS "Using gRPC ${gRPC_VERSION}") + +set(_GRPC_GRPCPP gRPC::grpc++) +set(_REFLECTION gRPC::grpc++_reflection) + +if (CMAKE_CROSSCOMPILING) + find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) + find_program(_GRPC_PYTHON_PLUGIN_EXECUTABLE grpc_python_plugin) +else () + set(_GRPC_CPP_PLUGIN_EXECUTABLE $) + set(_GRPC_PYTHON_PLUGIN_EXECUTABLE $) +endif () + +# Proto file +get_filename_component(hw_proto "ms_service.proto" ABSOLUTE) +get_filename_component(hw_proto_path ${hw_proto} PATH) +# Generated sources +set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/ms_service.pb.cc") +set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ms_service.pb.h") +set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/ms_service.grpc.pb.cc") +set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/ms_service.grpc.pb.h") +set(hw_py_pb2 "${CMAKE_CURRENT_BINARY_DIR}/ms_service_pb2.py") +set(hw_py_pb2_grpc "${CMAKE_CURRENT_BINARY_DIR}/ms_service_pb2_grpc.py") +add_custom_command( + OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" "${hw_py_pb2}" "${hw_py_pb2_grpc}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${hw_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" + "${hw_proto}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --python_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${hw_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_PYTHON_PLUGIN_EXECUTABLE}" + "${hw_proto}" + DEPENDS "${hw_proto}") + +list(APPEND SERVING_SRC_TEST ${hw_proto_srcs} ${hw_grpc_srcs}) + +file(GLOB_RECURSE ACL_SESSION_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "../../../../serving/acl/*.cc" + "../../../../serving/core/*.cc") +list(APPEND SERVING_SRC_TEST ${ACL_SESSION_SRC_LIST}) + +# utest files +file(GLOB_RECURSE ACL_UTEST_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc") +list(APPEND SERVING_SRC_TEST ${ACL_UTEST_SRC_LIST}) + +include_directories(${CMAKE_SOURCE_DIR}/serving/core) +include_directories(${CMAKE_SOURCE_DIR}/serving/acl) +include_directories(${CMAKE_SOURCE_DIR}/serving) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../) +add_library(ut_serving_obj OBJECT ${SERVING_SRC_TEST}) + + diff --git a/tests/ut/cpp/serving/acl/acl.h b/tests/ut/cpp/serving/acl/acl.h new file mode 100644 index 0000000000000000000000000000000000000000..0719ac8a0c584bade4cf20c0e20ad8e9775e06d9 --- /dev/null +++ b/tests/ut/cpp/serving/acl/acl.h @@ -0,0 +1,26 @@ +/** + * Copyright 2020 Huawei Technologies 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 ACL_STUB_INC_ACL_H +#define ACL_STUB_INC_ACL_H +#include "acl_base.h" +#include "acl_mdl.h" +#include "acl_rt.h" + +aclError aclInit(const char *configPath); +aclError aclFinalize(); + +#endif // ACL_STUB_INC_ACL_H \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl/acl_base.h b/tests/ut/cpp/serving/acl/acl_base.h new file mode 100644 index 0000000000000000000000000000000000000000..3bab6a4a7b60700082a94f93737f0868eec92eab --- /dev/null +++ b/tests/ut/cpp/serving/acl/acl_base.h @@ -0,0 +1,85 @@ +/** + * Copyright 2020 Huawei Technologies 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 ACL_STUB_INC_ACL_BASE +#define ACL_STUB_INC_ACL_BASE +#include +#include + +typedef void *aclrtStream; +typedef void *aclrtEvent; +typedef void *aclrtContext; +typedef int aclError; +typedef uint16_t aclFloat16; +typedef struct aclDataBuffer aclDataBuffer; +typedef struct aclTensorDesc aclTensorDesc; + +const int ACL_ERROR_NONE = 0; + +typedef enum { + ACL_DT_UNDEFINED = -1, + ACL_FLOAT = 0, + ACL_FLOAT16 = 1, + ACL_INT8 = 2, + ACL_INT32 = 3, + ACL_UINT8 = 4, + ACL_INT16 = 6, + ACL_UINT16 = 7, + ACL_UINT32 = 8, + ACL_INT64 = 9, + ACL_UINT64 = 10, + ACL_DOUBLE = 11, + ACL_BOOL = 12, +} aclDataType; + +typedef enum { + ACL_FORMAT_UNDEFINED = -1, + ACL_FORMAT_NCHW = 0, + ACL_FORMAT_NHWC = 1, + ACL_FORMAT_ND = 2, + ACL_FORMAT_NC1HWC0 = 3, + ACL_FORMAT_FRACTAL_Z = 4, + ACL_FORMAT_FRACTAL_NZ = 29, + +} aclFormat; + +typedef enum { + ACL_DEBUG, + ACL_INFO, + ACL_WARNING, + ACL_ERROR, +} aclLogLevel; + +aclDataBuffer *aclCreateDataBuffer(void *data, size_t size); +aclError aclDestroyDataBuffer(const aclDataBuffer *dataBuffer); +void *aclGetDataBufferAddr(const aclDataBuffer *dataBuffer); +uint32_t aclGetDataBufferSize(const aclDataBuffer *dataBuffer); +size_t aclDataTypeSize(aclDataType dataType); + +aclTensorDesc *aclCreateTensorDesc(aclDataType dataType, int numDims, const int64_t *dims, aclFormat format); +void aclDestroyTensorDesc(const aclTensorDesc *desc); +aclDataType aclGetTensorDescType(const aclTensorDesc *desc); +aclFormat aclGetTensorDescFormat(const aclTensorDesc *desc); +size_t aclGetTensorDescSize(const aclTensorDesc *desc); +size_t aclGetTensorDescElementCount(const aclTensorDesc *desc); +size_t aclGetTensorDescNumDims(const aclTensorDesc *desc); +int64_t aclGetTensorDescDim(const aclTensorDesc *desc, size_t index); + +void aclAppLog(aclLogLevel logLevel, const char *func, const char *file, uint32_t line, const char *fmt, ...); + +#define ACL_APP_LOG(level, fmt, ...) aclAppLog(level, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#endif \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl/acl_mdl.h b/tests/ut/cpp/serving/acl/acl_mdl.h new file mode 100644 index 0000000000000000000000000000000000000000..ccec700f596382672abf502c068bf82e4671c64b --- /dev/null +++ b/tests/ut/cpp/serving/acl/acl_mdl.h @@ -0,0 +1,75 @@ +/** + * Copyright 2020 Huawei Technologies 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 ACL_STUB_INC_ACL_MDL +#define ACL_STUB_INC_ACL_MDL +#include "acl_base.h" + +#define ACL_MAX_DIM_CNT 128 +#define ACL_MAX_TENSOR_NAME_LEN 128 +#define ACL_MAX_BATCH_NUM 128 +#define ACL_MAX_HW_NUM 128 +#define ACL_MAX_SHAPE_COUNT 128 + +typedef struct aclmdlDataset aclmdlDataset; +typedef struct aclmdlDesc aclmdlDesc; + +typedef struct aclmdlIODims { + char name[ACL_MAX_TENSOR_NAME_LEN]; + size_t dimCount; + int64_t dims[ACL_MAX_DIM_CNT]; +} aclmdlIODims; + +aclmdlDesc *aclmdlCreateDesc(); +aclError aclmdlDestroyDesc(aclmdlDesc *modelDesc); +aclError aclmdlGetDesc(aclmdlDesc *modelDesc, uint32_t modelId); + +size_t aclmdlGetNumInputs(aclmdlDesc *modelDesc); +size_t aclmdlGetNumOutputs(aclmdlDesc *modelDesc); +size_t aclmdlGetInputSizeByIndex(aclmdlDesc *modelDesc, size_t index); +size_t aclmdlGetOutputSizeByIndex(aclmdlDesc *modelDesc, size_t index); + +aclmdlDataset *aclmdlCreateDataset(); +aclError aclmdlDestroyDataset(const aclmdlDataset *dataSet); +aclError aclmdlAddDatasetBuffer(aclmdlDataset *dataSet, aclDataBuffer *dataBuffer); +size_t aclmdlGetDatasetNumBuffers(const aclmdlDataset *dataSet); +aclDataBuffer *aclmdlGetDatasetBuffer(const aclmdlDataset *dataSet, size_t index); + +aclError aclmdlLoadFromFile(const char *modelPath, uint32_t *modelId); +aclError aclmdlLoadFromMem(const void *model, size_t modelSize, uint32_t *modelId); +aclError aclmdlLoadFromFileWithMem(const char *modelPath, uint32_t *modelId, void *workPtr, size_t workSize, + void *weightPtr, size_t weightSize); +aclError aclmdlLoadFromMemWithMem(const void *model, size_t modelSize, uint32_t *modelId, void *workPtr, + size_t workSize, void *weightPtr, size_t weightSize); + +aclError aclmdlExecute(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output); +aclError aclmdlExecuteAsync(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output, aclrtStream stream); +aclError aclmdlUnload(uint32_t modelId); + +aclError aclmdlQuerySize(const char *fileName, size_t *workSize, size_t *weightSize); +aclError aclmdlQuerySizeFromMem(const void *model, size_t modelSize, size_t *workSize, size_t *weightSize); + +aclError aclmdlGetInputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims); +aclError aclmdlGetOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims); +aclError aclmdlGetCurOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims); + +aclFormat aclmdlGetInputFormat(const aclmdlDesc *modelDesc, size_t index); +aclFormat aclmdlGetOutputFormat(const aclmdlDesc *modelDesc, size_t index); + +aclDataType aclmdlGetInputDataType(const aclmdlDesc *modelDesc, size_t index); +aclDataType aclmdlGetOutputDataType(const aclmdlDesc *modelDesc, size_t index); + +#endif \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl/acl_rt.h b/tests/ut/cpp/serving/acl/acl_rt.h new file mode 100644 index 0000000000000000000000000000000000000000..e36e4cf45a395f95007b4df563328b5f58121eaa --- /dev/null +++ b/tests/ut/cpp/serving/acl/acl_rt.h @@ -0,0 +1,89 @@ +/** + * Copyright 2020 Huawei Technologies 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 ACL_STUB_INC_ACL_RT_H +#define ACL_STUB_INC_ACL_RT_H +#include "acl_base.h" + +typedef enum aclrtRunMode { + ACL_DEVICE, + ACL_HOST, +} aclrtRunMode; + +typedef enum aclrtTsId { + ACL_TS_ID_AICORE, + ACL_TS_ID_AIVECTOR, + ACL_TS_ID_RESERVED, +} aclrtTsId; + +typedef enum aclrtEventStatus { + ACL_EVENT_STATUS_COMPLETE, + ACL_EVENT_STATUS_NOT_READY, + ACL_EVENT_STATUS_RESERVED, +} aclrtEventStatus; + +typedef enum aclrtCallbackBlockType { + ACL_CALLBACK_NO_BLOCK, + ACL_CALLBACK_BLOCK, +} aclrtCallbackBlockType; + +typedef enum aclrtMemcpyKind { + ACL_MEMCPY_HOST_TO_HOST, + ACL_MEMCPY_HOST_TO_DEVICE, + ACL_MEMCPY_DEVICE_TO_HOST, + ACL_MEMCPY_DEVICE_TO_DEVICE, +} aclrtMemcpyKind; + +typedef enum aclrtMemMallocPolicy { + ACL_MEM_MALLOC_HUGE_FIRST, + ACL_MEM_MALLOC_HUGE_ONLY, + ACL_MEM_MALLOC_NORMAL_ONLY, +} aclrtMemMallocPolicy; + +typedef struct rtExceptionInfo aclrtExceptionInfo; +typedef void (*aclrtCallback)(void *userData); +typedef void (*aclrtExceptionInfoCallback)(aclrtExceptionInfo *exceptionInfo); + +aclError aclrtCreateContext(aclrtContext *context, int32_t deviceId); +aclError aclrtDestroyContext(aclrtContext context); +aclError aclrtSetCurrentContext(aclrtContext context); +aclError aclrtGetCurrentContext(aclrtContext *context); +aclError aclrtSetDevice(int32_t deviceId); +aclError aclrtResetDevice(int32_t deviceId); +aclError aclrtGetDevice(int32_t *deviceId); +aclError aclrtGetRunMode(aclrtRunMode *runMode); +aclError aclrtSynchronizeDevice(void); +aclError aclrtSetTsDevice(aclrtTsId tsId); +aclError aclrtGetDeviceCount(uint32_t *count); + +aclError aclrtMalloc(void **devPtr, size_t size, aclrtMemMallocPolicy policy); +aclError aclrtFree(void *devPtr); + +aclError aclrtMallocHost(void **hostPtr, size_t size); +aclError aclrtFreeHost(void *hostPtr); + +aclError aclrtMemcpy(void *dst, size_t destMax, const void *src, size_t count, aclrtMemcpyKind kind); +aclError aclrtMemset(void *devPtr, size_t maxCount, int32_t value, size_t count); +aclError aclrtMemcpyAsync(void *dst, size_t destMax, const void *src, size_t count, aclrtMemcpyKind kind, + aclrtStream stream); +aclError aclrtMemsetAsync(void *devPtr, size_t maxCount, int32_t value, size_t count, aclrtStream stream); + +aclError aclrtCreateStream(aclrtStream *stream); +aclError aclrtDestroyStream(aclrtStream stream); +aclError aclrtSynchronizeStream(aclrtStream stream); +aclError aclrtStreamWaitEvent(aclrtStream stream, aclrtEvent event); + +#endif \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl/ops/acl_dvpp.h b/tests/ut/cpp/serving/acl/ops/acl_dvpp.h new file mode 100644 index 0000000000000000000000000000000000000000..b66ca8ec21f68a625c9b9ff35ef984cd6bfa9946 --- /dev/null +++ b/tests/ut/cpp/serving/acl/ops/acl_dvpp.h @@ -0,0 +1,112 @@ +/** + * Copyright 2020 Huawei Technologies 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 ACL_STUB_INC_ACL_DVPP_H +#define ACL_STUB_INC_ACL_DVPP_H +#include +#include "acl/acl.h" +#include "acl/acl_base.h" + +typedef struct acldvppPicDesc acldvppPicDesc; +typedef struct acldvppRoiConfig acldvppRoiConfig; +typedef struct acldvppResizeConfig acldvppResizeConfig; +typedef struct acldvppChannelDesc acldvppChannelDesc; +typedef struct acldvppStreamDesc acldvppStreamDesc; +typedef struct acldvppBatchPicDesc acldvppBatchPicDesc; + +enum acldvppPixelFormat { + PIXEL_FORMAT_YUV_400 = 0, + PIXEL_FORMAT_YUV_SEMIPLANAR_420 = 1, // YUV + PIXEL_FORMAT_YVU_SEMIPLANAR_420 = 2, // YVU + PIXEL_FORMAT_YUV_SEMIPLANAR_422 = 3, // YUV + PIXEL_FORMAT_YVU_SEMIPLANAR_422 = 4, // YVU + PIXEL_FORMAT_YUV_SEMIPLANAR_444 = 5, // YUV + PIXEL_FORMAT_YVU_SEMIPLANAR_444 = 6, // YVU + +}; + +enum acldvppStreamFormat { + H265_MAIN_LEVEL = 0, + H254_BASELINE_LEVEL = 1, + H254_MAIN_LEVEL, + H254_HIGH_LEVEL, +}; + +enum acldvppChannelMode { DVPP_CHNMODE_VPC = 1, DVPP_CHNMODE_JPEGD = 2, DVPP_CHNMODE_JPEGE = 4 }; + +aclError acldvppMalloc(void **devPtr, size_t size); +aclError acldvppFree(void *devPtr); +acldvppChannelDesc *acldvppCreateChannelDesc(); +aclError acldvppDestroyChannelDesc(acldvppChannelDesc *channelDesc); +acldvppPicDesc *acldvppCreatePicDesc(); +aclError acldvppDestroyPicDesc(acldvppPicDesc *picDesc); +aclError acldvppSetPicDescSize(acldvppPicDesc *picDesc, uint32_t size); +aclError acldvppSetPicDescFormat(acldvppPicDesc *picDesc, acldvppPixelFormat format); +aclError acldvppSetPicDescWidth(acldvppPicDesc *picDesc, uint32_t width); +aclError acldvppSetPicDescHeight(acldvppPicDesc *picDesc, uint32_t height); +aclError acldvppSetPicDescData(acldvppPicDesc *picDesc, void *dataDev); +aclError acldvppSetPicDescWidthStride(acldvppPicDesc *picDesc, uint32_t widthStride); +aclError acldvppSetPicDescHeightStride(acldvppPicDesc *picDesc, uint32_t heightStride); +aclError acldvppSetPicDescRetCode(acldvppPicDesc *picDesc, uint32_t retCode); + +uint32_t acldvppGetPicDescSize(acldvppPicDesc *picDesc); +acldvppPixelFormat acldvppGetPicDescFormat(acldvppPicDesc *picDesc); +uint32_t acldvppGetPicDescWidth(acldvppPicDesc *picDesc); +uint32_t acldvppGetPicDescHeight(acldvppPicDesc *picDesc); +void *acldvppGetPicDescData(acldvppPicDesc *picDesc); +uint32_t acldvppGetPicDescWidthStride(acldvppPicDesc *picDesc); +uint32_t acldvppGetPicDescHeightStride(acldvppPicDesc *picDesc); +uint32_t acldvppGetPicDescRetCode(acldvppPicDesc *picDesc); + +acldvppRoiConfig *acldvppCreateRoiConfig(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom); +aclError acldvppDestroyRoiConfig(acldvppRoiConfig *roiConfig); +aclError acldvppSetRoiConfigLeft(acldvppRoiConfig *roiConfig, uint32_t left); +aclError acldvppSetRoiConfigRight(acldvppRoiConfig *roiConfig, uint32_t right); +aclError acldvppSetRoiConfigTop(acldvppRoiConfig *roiConfig, uint32_t top); +aclError acldvppSetRoiConfigBottom(acldvppRoiConfig *roiConfig, uint32_t bottom); +aclError acldvppSetRoiConfig(acldvppRoiConfig *roiConfig, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom); + +acldvppResizeConfig *acldvppCreateResizeConfig(); +aclError acldvppDestroyResizeConfig(acldvppResizeConfig *resizeConfig); + +aclError acldvppJpegPredictDecSize(const void *data, uint32_t dataSize, acldvppPixelFormat ouputPixelFormat, + uint32_t *decSize); + +aclError acldvppCreateChannel(acldvppChannelDesc *channelDesc); +aclError acldvppDestroyChannel(acldvppChannelDesc *channelDesc); + +aclError acldvppVpcResizeAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppResizeConfig *resizeConfig, aclrtStream stream); + +aclError acldvppVpcCropAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppRoiConfig *cropArea, aclrtStream stream); + +aclError acldvppVpcCropAndPasteAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppRoiConfig *cropArea, + acldvppRoiConfig *pasteArea, aclrtStream stream); + +aclError acldvppVpcBatchCropAsync(acldvppChannelDesc *channelDesc, acldvppBatchPicDesc *srcBatchDesc, uint32_t *roiNums, + uint32_t size, acldvppBatchPicDesc *dstBatchDesc, acldvppRoiConfig *cropAreas[], + aclrtStream stream); + +aclError acldvppJpegDecodeAsync(acldvppChannelDesc *channelDesc, const void *data, uint32_t size, + acldvppPicDesc *outputDesc, aclrtStream stream); + +acldvppBatchPicDesc *acldvppCreateBatchPicDesc(uint32_t batchSize); +acldvppPicDesc *acldvppGetPicDesc(acldvppBatchPicDesc *batchPicDesc, uint32_t index); +aclError acldvppDestroyBatchPicDesc(acldvppBatchPicDesc *batchPicDesc); + +#endif // ACL_STUB_INC_ACL_DVPP_H \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_session_test_add.cc b/tests/ut/cpp/serving/acl_session_test_add.cc new file mode 100644 index 0000000000000000000000000000000000000000..3156798037064af62b0acd11b914a2cd6239c84b --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_add.cc @@ -0,0 +1,163 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_session_test_common.h" + +using namespace std; + +namespace mindspore { +namespace serving { + +class AclSessionAddTest : public AclSessionTest { + public: + AclSessionAddTest() = default; + void SetUp() override { + AclSessionTest::SetUp(); + aclmdlDesc model_desc; + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + mock_model_desc_ = MockModelDesc(model_desc); + g_acl_model_desc = &mock_model_desc_; + g_acl_model = &add_mock_model_; + } + void CreateDefaultRequest(PredictRequest &request) { + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + auto input1 = request.add_data(); + CreateTensor(*input1, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + + auto input0_data = reinterpret_cast(input0->mutable_data()->data()); + auto input1_data = reinterpret_cast(input1->mutable_data()->data()); + for (int i = 0; i < 2 * 24 * 24 * 3; i++) { + input0_data[i] = i % 1024; + input1_data[i] = i % 1024 + 1; + } + } + + void CheckDefaultReply(const PredictReply &reply) { + EXPECT_TRUE(reply.result().size() == 1); + if (reply.result().size() == 1) { + CheckTensorItem(reply.result(0), {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + auto &output = reply.result(0).data(); + EXPECT_EQ(output.size(), 2 * 24 * 24 * 3 * sizeof(float)); + if (output.size() == 2 * 24 * 24 * 3 * sizeof(float)) { + auto output_data = reinterpret_cast(output.data()); + for (int i = 0; i < 2 * 24 * 24 * 3; i++) { + EXPECT_EQ(output_data[i], (i % 1024) + (i % 1024 + 1)); + if (output_data[i] != (i % 1024) + (i % 1024 + 1)) { + break; + } + } + } + } + } + MockModelDesc mock_model_desc_; + AddMockAclModel add_mock_model_; +}; + +TEST_F(AclSessionAddTest, TestAclSession_OneTime_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionAddTest, TestAclSession_MutilTimes_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionAddTest, TestAclSession_DeviceRunMode_OneTime_Success) { + SetDeviceRunMode(); + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionAddTest, TestAclSession_DeviceRunMode_MutilTimes_Success) { + SetDeviceRunMode(); + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +} // namespace serving +} // namespace mindspore \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_session_test_common.h b/tests/ut/cpp/serving/acl_session_test_common.h new file mode 100644 index 0000000000000000000000000000000000000000..39a0514bca60986d4cdb545f415256e6d7c72f83 --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_common.h @@ -0,0 +1,191 @@ +/** + * Copyright 2020 Huawei Technologies 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 MINDSPORE_ACL_SESSION_TEST_COMMON_H +#define MINDSPORE_ACL_SESSION_TEST_COMMON_H + +#include "common/common_test.h" +#include "serving/core/server.h" +#include "include/inference.h" +#include "include/infer_tensor.h" +#include "serving/core/serving_tensor.h" +#include "serving/acl/acl_session.h" +#include "serving/acl/model_process.h" +#include "serving/acl/dvpp_process.h" +#include "acl_stub.h" + +class MockDeviceRunMode : public AclRunMode { + public: + aclError aclrtGetRunMode(aclrtRunMode *runMode) override { + *runMode = aclrtRunMode::ACL_DEVICE; + return ACL_ERROR_NONE; + } +}; + +class AclSessionTest : public testing::Test { + public: + AclSessionTest() = default; + void SetUp() override { + g_acl_data_buffer = &g_acl_data_buffer_default; + g_acl_env = &g_acl_env_default; + g_acl_dataset = &g_acl_dataset_default; + g_acl_model = &g_acl_model_default; + g_acl_model_desc = &g_acl_model_desc_default; + g_acl_device_context_stream = &g_acl_device_context_stream_default; + g_acl_memory = &g_acl_memory_default; + g_acl_dvpp_pic_desc = &g_acl_dvpp_pic_desc_default; + g_acl_dvpp_roi_config = &g_acl_dvpp_roi_config_default; + g_acl_dvpp_resize_config = &g_acl_dvpp_resize_config_default; + g_acl_dvpp_channel_desc = &g_acl_dvpp_channel_desc_default; + g_acl_dvpp_process = &g_acl_dvpp_process_default; + g_acl_run_mode = &acl_run_mode_default; + g_acl_jpeg_lib = &acl_jpeg_lib_default; + } + void TearDown() override { + EXPECT_TRUE(g_acl_data_buffer->Check()); + EXPECT_TRUE(g_acl_env->Check()); + EXPECT_TRUE(g_acl_dataset->Check()); + EXPECT_TRUE(g_acl_model->Check()); + EXPECT_TRUE(g_acl_model_desc->Check()); + EXPECT_TRUE(g_acl_device_context_stream->Check()); + EXPECT_TRUE(g_acl_memory->Check()); + EXPECT_TRUE(g_acl_dvpp_pic_desc->Check()); + EXPECT_TRUE(g_acl_dvpp_roi_config->Check()); + EXPECT_TRUE(g_acl_dvpp_resize_config->Check()); + EXPECT_TRUE(g_acl_dvpp_channel_desc->Check()); + EXPECT_TRUE(g_acl_dvpp_process->Check()); + EXPECT_TRUE(g_acl_jpeg_lib->Check()); + } + + AclDataBuffer g_acl_data_buffer_default; + AclEnv g_acl_env_default; + AclDataSet g_acl_dataset_default; + AclModel g_acl_model_default; + AclModelDesc g_acl_model_desc_default; + AclDeviceContextStream g_acl_device_context_stream_default; + AclMemory g_acl_memory_default; + AclDvppPicDesc g_acl_dvpp_pic_desc_default; + AclDvppRoiConfig g_acl_dvpp_roi_config_default; + AclDvppResizeConfig g_acl_dvpp_resize_config_default; + AclDvppChannelDesc g_acl_dvpp_channel_desc_default; + AclDvppProcess g_acl_dvpp_process_default; + AclRunMode acl_run_mode_default; + MockDeviceRunMode acl_device_run_mode; + AclJpegLib acl_jpeg_lib_default = AclJpegLib(0, 0); + + void SetDeviceRunMode() { g_acl_run_mode = &acl_device_run_mode; } + void CreateTensor(ms_serving::Tensor &tensor, const std::vector &shape, ms_serving::DataType data_type, + std::size_t data_size = INT64_MAX) { + if (data_size == INT64_MAX) { + data_size = GetDataTypeSize(data_type); + for (auto item : shape) { + data_size *= item; + } + } + tensor.set_data(std::string(data_size, 0)); + tensor.set_tensor_type(data_type); + auto tensor_shape = tensor.mutable_tensor_shape(); + for (auto item : shape) { + tensor_shape->add_dims(item); + } + } + + size_t GetDataTypeSize(ms_serving::DataType data_type) { + const std::map type_size_map{ + {ms_serving::DataType::MS_BOOL, sizeof(bool)}, {ms_serving::DataType::MS_INT8, sizeof(int8_t)}, + {ms_serving::DataType::MS_UINT8, sizeof(uint8_t)}, {ms_serving::DataType::MS_INT16, sizeof(int16_t)}, + {ms_serving::DataType::MS_UINT16, sizeof(uint16_t)}, {ms_serving::DataType::MS_INT32, sizeof(int32_t)}, + {ms_serving::DataType::MS_UINT32, sizeof(uint32_t)}, {ms_serving::DataType::MS_INT64, sizeof(int64_t)}, + {ms_serving::DataType::MS_UINT64, sizeof(uint64_t)}, {ms_serving::DataType::MS_FLOAT16, 2}, + {ms_serving::DataType::MS_FLOAT32, sizeof(float)}, {ms_serving::DataType::MS_FLOAT64, sizeof(double)}, + }; + auto it = type_size_map.find(data_type); + if (it == type_size_map.end()) { + EXPECT_TRUE(false); + return 0; + } + return it->second; + } + + void CheckTensorItem(const ms_serving::Tensor &tensor, const std::vector &expect_shape, + ms_serving::DataType expect_data_type) { + std::vector tensor_shape; + for (auto item : tensor.tensor_shape().dims()) { + tensor_shape.push_back(item); + } + EXPECT_EQ(expect_shape, tensor_shape); + EXPECT_EQ(expect_data_type, tensor.tensor_type()); + int64_t elem_cnt = 1; + for (auto item : expect_shape) { + elem_cnt *= item; + } + auto data_size = GetDataTypeSize(expect_data_type); + EXPECT_EQ(data_size * elem_cnt, tensor.data().size()); + } +}; + +class MockModelDesc : public AclModelDesc { + public: + MockModelDesc() {} + MockModelDesc(const aclmdlDesc &mock_model_desc) : mock_model_desc_(mock_model_desc) {} + aclmdlDesc *aclmdlCreateDesc() override { + aclmdlDesc *model_desc = AclModelDesc::aclmdlCreateDesc(); + *model_desc = mock_model_desc_; + return model_desc; + } + aclmdlDesc mock_model_desc_; +}; + +class AddMockAclModel : public AclModel { + public: + aclError aclmdlExecute(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output) override { + if (AclModel::aclmdlExecute(modelId, input, output) != ACL_ERROR_NONE) { + return 1; + } + if (input->data_buffers.size() != 2) { + return 1; + } + auto &input0 = input->data_buffers[0]; + auto &input1 = input->data_buffers[1]; + std::size_t expect_count = input0->size / sizeof(float); + if (input0->size != expect_count * sizeof(float) || input1->size != expect_count * sizeof(float)) { + return 1; + } + + if (output->data_buffers.size() != 1) { + return 1; + } + auto &output0 = output->data_buffers[0]; + if (output0->size != expect_count * sizeof(float)) { + return 1; + } + + auto input0_data = reinterpret_cast(input0->data); + auto input1_data = reinterpret_cast(input1->data); + auto output0_data = reinterpret_cast(output0->data); + for (size_t i = 0; i < expect_count; i++) { + output0_data[i] = input0_data[i] + input1_data[i]; + } + return ACL_ERROR_NONE; + } + + aclError aclmdlExecuteAsync(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output, + aclrtStream stream) override { + return aclmdlExecute(modelId, input, output); + } +}; + +#endif // MINDSPORE_ACL_SESSION_TEST_COMMON_H diff --git a/tests/ut/cpp/serving/acl_session_test_dvpp.cc b/tests/ut/cpp/serving/acl_session_test_dvpp.cc new file mode 100644 index 0000000000000000000000000000000000000000..6a3f01e02c4b86a4b26cd608f871ba4db5124165 --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_dvpp.cc @@ -0,0 +1,1055 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_session_test_common.h" +#include +#include +#include + +using namespace std; +using namespace mindspore::inference; + +namespace mindspore { +namespace serving { + +class MockDvppProces : public AclDvppProcess { + public: + aclError acldvppVpcResizeAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppResizeConfig *resizeConfig, aclrtStream stream) override { + if (resize_fail_list_.empty()) { + return AclDvppProcess::acldvppVpcResizeAsync(channelDesc, inputDesc, outputDesc, resizeConfig, stream); + } + bool val = resize_fail_list_.front(); + resize_fail_list_.erase(resize_fail_list_.begin()); + if (!val) { + return 1; + } + return AclDvppProcess::acldvppVpcResizeAsync(channelDesc, inputDesc, outputDesc, resizeConfig, stream); + } + aclError acldvppVpcCropAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppRoiConfig *cropArea, aclrtStream stream) override { + if (crop_fail_list_.empty()) { + return AclDvppProcess::acldvppVpcCropAsync(channelDesc, inputDesc, outputDesc, cropArea, stream); + } + bool val = crop_fail_list_.front(); + crop_fail_list_.erase(crop_fail_list_.begin()); + if (!val) { + return 1; + } + return AclDvppProcess::acldvppVpcCropAsync(channelDesc, inputDesc, outputDesc, cropArea, stream); + } + aclError acldvppVpcCropAndPasteAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppRoiConfig *cropArea, + acldvppRoiConfig *pasteArea, aclrtStream stream) override { + if (crop_and_paste_fail_list_.empty()) { + return AclDvppProcess::acldvppVpcCropAndPasteAsync(channelDesc, inputDesc, outputDesc, cropArea, pasteArea, + stream); + } + bool val = crop_and_paste_fail_list_.front(); + crop_and_paste_fail_list_.erase(crop_and_paste_fail_list_.begin()); + if (!val) { + return 1; + } + return AclDvppProcess::acldvppVpcCropAndPasteAsync(channelDesc, inputDesc, outputDesc, cropArea, pasteArea, stream); + } + aclError acldvppJpegDecodeAsync(acldvppChannelDesc *channelDesc, const void *data, uint32_t size, + acldvppPicDesc *outputDesc, aclrtStream stream) override { + if (decode_fail_list_.empty()) { + return AclDvppProcess::acldvppJpegDecodeAsync(channelDesc, data, size, outputDesc, stream); + } + bool val = decode_fail_list_.front(); + decode_fail_list_.erase(decode_fail_list_.begin()); + if (!val) { + return 1; + } + return AclDvppProcess::acldvppJpegDecodeAsync(channelDesc, data, size, outputDesc, stream); + } + vector decode_fail_list_; + vector resize_fail_list_; + vector crop_fail_list_; + vector crop_and_paste_fail_list_; +}; + +class AclSessionDvppTest : public AclSessionTest { + public: + AclSessionDvppTest() = default; + void SetUp() override { AclSessionTest::SetUp(); } + void InitModelDesc(uint32_t batch_size) { + batch_size_ = batch_size; + aclmdlDesc model_desc; + model_desc.inputs.push_back( // 32-> 16 align, 24->2 align + AclTensorDesc{ + .dims = {batch_size_, 32, 24, 3}, .data_type = ACL_FLOAT, .size = batch_size_ * 32 * 24 * 3 / 2}); // YUV420SP + + model_desc.outputs.push_back(AclTensorDesc{ + .dims = {batch_size_, 24, 24, 3}, .data_type = ACL_FLOAT, .size = batch_size_ * 24 * 24 * 3 * sizeof(float)}); + + model_desc.outputs.push_back(AclTensorDesc{ + .dims = {batch_size_, 24, 24, 3}, .data_type = ACL_FLOAT, .size = batch_size_ * 24 * 24 * 3 * sizeof(float)}); + + mock_model_desc_ = MockModelDesc(model_desc); + g_acl_model_desc = &mock_model_desc_; + g_acl_dvpp_process = &mock_dvpp_process_; + } + void TearDown() override { + AclSessionTest::TearDown(); + remove(dvpp_config_file_path_.c_str()); + } + void CreateDefaultRequest(PredictRequest &request, uint32_t image_size = 1) { + auto input0 = request.add_images(); + for (uint32_t i = 0; i < batch_size_; i++) { + input0->add_images(std::string(image_size, '\0')); // any length data + } + } + + void CheckDefaultReply(const PredictReply &reply) { + EXPECT_TRUE(reply.result().size() == 2); + if (reply.result().size() == 2) { + CheckTensorItem(reply.result(0), {batch_size_, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + CheckTensorItem(reply.result(1), {batch_size_, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + } + + void WriteDvppConfig(const std::string &dvpp_config_context) { + std::ofstream fp(dvpp_config_file_path_); + ASSERT_TRUE(fp.is_open()); + if (fp.is_open()) { + fp << dvpp_config_context; + } + } + + void SetJpegLib(uint32_t image_width, uint32_t image_height, J_COLOR_SPACE color_space = JCS_YCbCr) { + acl_jpeg_lib_default.image_width_ = image_width; + acl_jpeg_lib_default.image_height_ = image_height; + acl_jpeg_lib_default.color_space_ = color_space; + } + + void CreateDvppConfig() { + nlohmann::json dvpp_config; + auto &preprocess_list = dvpp_config["preprocess"]; + auto &preprocess = preprocess_list[0]; + preprocess["input"]["index"] = 0; + preprocess["decode_para"]["out_pixel_format"] = pixel_format_; + auto &dvpp_process = preprocess["dvpp_process"]; + + if (to_resize_flag_) { + dvpp_process["op_name"] = "resize"; + dvpp_process["out_width"] = resize_para_.output_width; + dvpp_process["out_height"] = resize_para_.output_height; + } else if (to_crop_flag_) { + auto &crop_info = crop_para_.crop_info; + auto &crop_area = crop_info.crop_area; + dvpp_process["op_name"] = "crop"; + dvpp_process["out_width"] = crop_para_.output_width; + dvpp_process["out_height"] = crop_para_.output_height; + if (crop_info.crop_type == kDvppCropTypeOffset) { + dvpp_process["crop_type"] = "offset"; + dvpp_process["crop_left"] = crop_area.left; + dvpp_process["crop_top"] = crop_area.top; + dvpp_process["crop_right"] = crop_area.right; + dvpp_process["crop_bottom"] = crop_area.bottom; + } else { + dvpp_process["crop_type"] = "centre"; + dvpp_process["crop_width"] = crop_info.crop_width; + dvpp_process["crop_height"] = crop_info.crop_height; + } + } else if (to_crop_and_paste_flag_) { + auto &crop_info = crop_paste_para_.crop_info; + auto &crop_area = crop_info.crop_area; + dvpp_process["op_name"] = "crop_and_paste"; + dvpp_process["out_width"] = crop_paste_para_.output_width; + dvpp_process["out_height"] = crop_paste_para_.output_height; + + dvpp_process["paste_left"] = crop_paste_para_.paste_area.left; + dvpp_process["paste_right"] = crop_paste_para_.paste_area.right; + dvpp_process["paste_top"] = crop_paste_para_.paste_area.top; + dvpp_process["paste_bottom"] = crop_paste_para_.paste_area.bottom; + + if (crop_info.crop_type == kDvppCropTypeOffset) { + dvpp_process["crop_type"] = "offset"; + dvpp_process["crop_left"] = crop_area.left; + dvpp_process["crop_top"] = crop_area.top; + dvpp_process["crop_right"] = crop_area.right; + dvpp_process["crop_bottom"] = crop_area.bottom; + } else { + dvpp_process["crop_type"] = "centre"; + dvpp_process["crop_width"] = crop_info.crop_width; + dvpp_process["crop_height"] = crop_info.crop_height; + } + } + stringstream output; + output << dvpp_config; + WriteDvppConfig(output.str()); + } + uint32_t batch_size_ = 1; + MockModelDesc mock_model_desc_; + MockDvppProces mock_dvpp_process_; + + const std::string model_file_path_ = "/tmp/acl_model_fake_path.om"; + const std::string dvpp_config_file_path_ = "/tmp/acl_model_fake_path_dvpp_config.json"; + inference::DvppResizePara resize_para_; + inference::DvppCropPara crop_para_; + inference::DvppCropAndPastePara crop_paste_para_; + bool to_resize_flag_ = false; + bool to_crop_flag_ = false; + bool to_crop_and_paste_flag_ = false; + std::string pixel_format_; +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize1_Success) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_Success) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 3); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 3); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCrop_BatchSize1_Success) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + crop_para_.output_width = 24; // align to 32 + crop_para_.output_height = 24; + crop_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_para_.crop_info.crop_area.left = 0; + crop_para_.crop_info.crop_area.right = 64; + crop_para_.crop_info.crop_area.top = 0; + crop_para_.crop_info.crop_area.bottom = 64; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->crop_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPaste_BatchSize1_Success) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + crop_paste_para_.output_width = 24; // align to 32 + crop_paste_para_.output_height = 24; + crop_paste_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_paste_para_.crop_info.crop_area.left = 0; + crop_paste_para_.crop_info.crop_area.right = 64; + crop_paste_para_.crop_info.crop_area.top = 0; + crop_paste_para_.crop_info.crop_area.bottom = 64; + crop_paste_para_.paste_area.left = 0; + crop_paste_para_.paste_area.right = 64; + crop_paste_para_.paste_area.top = 0; + crop_paste_para_.paste_area.bottom = 64; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->crop_paste_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_MultiTime_Success) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + for (int i = 0; i < 3; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request, i + 1); // image size + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 3 * 3); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 3 * 3); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_MultiTime_SameImageSize_Success) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + for (int i = 0; i < 3; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request, 1); // image size + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 3 * 3); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 3 * 3); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_InvalidImageDim_Fail) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + SetJpegLib(31, 31); // 32*32 ~ 4096*4096 + { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + } + SetJpegLib(4097, 4097); // 32*32 ~ 4096*4096 + { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 0); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 0); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_InvalidResizeWidth_Fail) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + resize_para_.output_width = 15; // align to 16 16n minimum 32 + resize_para_.output_height = 24; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_width failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->resize_call_times_, 0); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 0); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_InvalidResizeHeight_Fail) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + resize_para_.output_width = 32; // align to 32 16n, minimum 32 + resize_para_.output_height = 3; // align to 4 2n, minimum 6 + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropOffset_CropMini_Success) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + crop_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_para_.output_height = 6; // align to 6 2n, minimum 6 + crop_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_para_.crop_info.crop_area.left = 4; + crop_para_.crop_info.crop_area.right = 13; + crop_para_.crop_info.crop_area.top = 4; + crop_para_.crop_info.crop_area.bottom = 9; + + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropCentre_CropMini_Success) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + crop_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_para_.crop_info.crop_width = 10; + crop_para_.crop_info.crop_height = 6; + + SetJpegLib(127, 127); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->crop_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropOffset_InvalidCropWidth_Fail) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + crop_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_para_.output_height = 6; // align to 6 2n, minimum 6 + crop_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_para_.crop_info.crop_area.left = 4; + crop_para_.crop_info.crop_area.right = 11; // minimum 10*6 + crop_para_.crop_info.crop_area.top = 4; + crop_para_.crop_info.crop_area.bottom = 9; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check crop width failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropOffset_InvalidCropHeight_Fail) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + crop_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_para_.output_height = 6; // align to 6 2n, minimum 6 + crop_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_para_.crop_info.crop_area.left = 4; + crop_para_.crop_info.crop_area.right = 13; + crop_para_.crop_info.crop_area.top = 4; + crop_para_.crop_info.crop_area.bottom = 7; // minimum 10*6 + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check crop height failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropCentre_InvalidCropHeight_Fail) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + crop_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_para_.crop_info.crop_width = 10; // minimum 10*6 + crop_para_.crop_info.crop_height = 4; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check crop_height failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPasteOffset_CropMini_Success) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + crop_paste_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_paste_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_paste_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_paste_para_.crop_info.crop_area.left = 4; + crop_paste_para_.crop_info.crop_area.right = 13; + crop_paste_para_.crop_info.crop_area.top = 4; + crop_paste_para_.crop_info.crop_area.bottom = 9; + crop_paste_para_.paste_area.left = 4; + crop_paste_para_.paste_area.right = 13; + crop_paste_para_.paste_area.top = 4; + crop_paste_para_.paste_area.bottom = 9; + + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->crop_paste_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPasteCentre_CropMini_Success) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + crop_paste_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_paste_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_paste_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_paste_para_.crop_info.crop_width = 10; + crop_paste_para_.crop_info.crop_height = 6; + crop_paste_para_.paste_area.left = 4; + crop_paste_para_.paste_area.right = 13; + crop_paste_para_.paste_area.top = 4; + crop_paste_para_.paste_area.bottom = 9; + + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->crop_paste_call_times_, 1); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPasteCentre_InvalidPasteWidth_Fail) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + crop_paste_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_paste_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_paste_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_paste_para_.crop_info.crop_width = 10; + crop_paste_para_.crop_info.crop_height = 6; + crop_paste_para_.paste_area.left = 4; + crop_paste_para_.paste_area.right = 11; + crop_paste_para_.paste_area.top = 4; + crop_paste_para_.paste_area.bottom = 9; + + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPasteCentre_InvalidPasteHeight_Fail) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + crop_paste_para_.output_width = 24; // align to 32 16n, minimum 32 + crop_paste_para_.output_height = 24; // align to 24 2n, minimum 6 + crop_paste_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_paste_para_.crop_info.crop_width = 10; + crop_paste_para_.crop_info.crop_height = 6; + crop_paste_para_.paste_area.left = 4; + crop_paste_para_.paste_area.right = 13; + crop_paste_para_.paste_area.top = 4; + crop_paste_para_.paste_area.bottom = 7; + + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + // load config, check output_height failed + EXPECT_FALSE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +// dvpp proces fail, test resource release ok +TEST_F(AclSessionDvppTest, TestAclSession_DvppDecode_BatchSize1_DvppFail) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + mock_dvpp_process_.decode_fail_list_.push_back(false); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize1_DvppFail) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + mock_dvpp_process_.resize_fail_list_.push_back(false); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_DvppFail0) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + mock_dvpp_process_.resize_fail_list_.push_back(false); // image 0 fail + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_DvppFail1) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + mock_dvpp_process_.resize_fail_list_.push_back(true); // image 0 success + mock_dvpp_process_.resize_fail_list_.push_back(false); // image 1 fail + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 2); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppResize_BatchSize3_DvppFail2) { + pixel_format_ = "YUV420SP"; + to_resize_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + resize_para_.output_width = 24; // align to 32 + resize_para_.output_height = 24; + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + mock_dvpp_process_.resize_fail_list_.push_back(true); // image 0 success + mock_dvpp_process_.resize_fail_list_.push_back(true); // image 1 success + mock_dvpp_process_.resize_fail_list_.push_back(false); // image 2 fail + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 3); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCrop_BatchSize1_DvppFail) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + crop_para_.output_width = 24; // align to 32 + crop_para_.output_height = 24; + crop_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_para_.crop_info.crop_area.left = 0; + crop_para_.crop_info.crop_area.right = 64; + crop_para_.crop_info.crop_area.top = 0; + crop_para_.crop_info.crop_area.bottom = 64; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + mock_dvpp_process_.crop_fail_list_.push_back(false); + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCropPaste_BatchSize1_DvppFail) { + pixel_format_ = "YUV420SP"; + to_crop_and_paste_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + crop_paste_para_.output_width = 24; // align to 32 + crop_paste_para_.output_height = 24; + crop_paste_para_.crop_info.crop_type = kDvppCropTypeOffset; + crop_paste_para_.crop_info.crop_area.left = 0; + crop_paste_para_.crop_info.crop_area.right = 64; + crop_paste_para_.crop_info.crop_area.top = 0; + crop_paste_para_.crop_info.crop_area.bottom = 64; + crop_paste_para_.paste_area.left = 0; + crop_paste_para_.paste_area.right = 64; + crop_paste_para_.paste_area.top = 0; + crop_paste_para_.paste_area.bottom = 64; + CreateDvppConfig(); + InitModelDesc(1); // batch_size=1 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + mock_dvpp_process_.crop_and_paste_fail_list_.push_back(false); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 1); +}; + +TEST_F(AclSessionDvppTest, TestAclSession_DvppCrop_BatchSize3_MultiTime_DvppFail) { + pixel_format_ = "YUV420SP"; + to_crop_flag_ = true; + SetJpegLib(128, 128); // 32*32 ~ 4096*4096 + crop_para_.output_width = 24; // align to 32 + crop_para_.output_height = 24; + crop_para_.crop_info.crop_type = kDvppCropTypeCentre; + crop_para_.crop_info.crop_width = 10; + crop_para_.crop_info.crop_height = 6; + + CreateDvppConfig(); + InitModelDesc(3); // batch_size=3 + + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile(model_file_path_, model_id) == SUCCESS); + + for (int i = 0; i < 3; i++) { + mock_dvpp_process_.crop_fail_list_.push_back(false); + // create inputs + PredictRequest request; + CreateDefaultRequest(request, i + 1); // image size + + PredictReply reply; + ServingRequest serving_request(request); + ServingImagesRequest serving_images(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_images, serving_request, serving_reply) == SUCCESS); + } + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); + EXPECT_EQ(g_acl_dvpp_process->decode_call_times_, 3); +}; + +} // namespace serving +} // namespace mindspore \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_session_test_model_load.cc b/tests/ut/cpp/serving/acl_session_test_model_load.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fe406fd55a44d881bc856d36b8140b747e96d8e --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_model_load.cc @@ -0,0 +1,342 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_session_test_common.h" + +using namespace std; + +namespace mindspore { +namespace serving { + +class MockFailAclDeviceContextStream : public AclDeviceContextStream { + public: + aclError aclrtSetDevice(int32_t deviceId) override { + if (set_device_fail_list_.empty()) { + return AclDeviceContextStream::aclrtSetDevice(deviceId); + } + auto val = set_device_fail_list_.front(); + set_device_fail_list_.erase(set_device_fail_list_.begin()); + if (val) { + return AclDeviceContextStream::aclrtSetDevice(deviceId); + } + return 1; + } + + aclError aclrtResetDevice(int32_t deviceId) override { + auto ret = AclDeviceContextStream::aclrtResetDevice(deviceId); + if (ret != ACL_ERROR_NONE) { + return ret; + } + if (reset_device_fail_list_.empty()) { + return ret; + } + auto val = reset_device_fail_list_.front(); + reset_device_fail_list_.erase(reset_device_fail_list_.begin()); + return val ? ACL_ERROR_NONE : 1; + } + + aclError aclrtCreateContext(aclrtContext *context, int32_t deviceId) override { + if (create_context_fail_list_.empty()) { + return AclDeviceContextStream::aclrtCreateContext(context, deviceId); + } + auto val = create_context_fail_list_.front(); + create_context_fail_list_.erase(create_context_fail_list_.begin()); + if (val) { + return AclDeviceContextStream::aclrtCreateContext(context, deviceId); + } + return 1; + } + + aclError aclrtDestroyContext(aclrtContext context) override { + auto ret = AclDeviceContextStream::aclrtDestroyContext(context); + if (ret != ACL_ERROR_NONE) { + return ret; + } + if (destroy_context_fail_list_.empty()) { + return ret; + } + auto val = destroy_context_fail_list_.front(); + destroy_context_fail_list_.erase(destroy_context_fail_list_.begin()); + return val ? ACL_ERROR_NONE : 1; + } + + aclError aclrtCreateStream(aclrtStream *stream) override { + if (create_stream_fail_list_.empty()) { + return AclDeviceContextStream::aclrtCreateStream(stream); + } + auto val = create_stream_fail_list_.front(); + create_stream_fail_list_.erase(create_stream_fail_list_.begin()); + if (val) { + return AclDeviceContextStream::aclrtCreateStream(stream); + } + return 1; + } + + aclError aclrtDestroyStream(aclrtStream stream) override { + auto ret = AclDeviceContextStream::aclrtDestroyStream(stream); + if (ret != ACL_ERROR_NONE) { + return ret; + } + if (destroy_stream_fail_list_.empty()) { + return ret; + } + auto val = destroy_stream_fail_list_.front(); + destroy_stream_fail_list_.erase(destroy_stream_fail_list_.begin()); + return val ? ACL_ERROR_NONE : 1; + } + std::vector set_device_fail_list_; + std::vector reset_device_fail_list_; + std::vector create_context_fail_list_; + std::vector destroy_context_fail_list_; + std::vector create_stream_fail_list_; + std::vector destroy_stream_fail_list_; +}; + +class MockFailAclMemory : public AclMemory { + public: + aclError aclrtMalloc(void **devPtr, size_t size, aclrtMemMallocPolicy policy) override { + if (device_mem_fail_list_.empty()) { + return AclMemory::aclrtMalloc(devPtr, size, policy); + } + auto val = device_mem_fail_list_.front(); + device_mem_fail_list_.erase(device_mem_fail_list_.begin()); + if (val) { + return AclMemory::aclrtMalloc(devPtr, size, policy); + } + return 1; + } + aclError aclrtMallocHost(void **hostPtr, size_t size) override { + if (host_mem_fail_list_.empty()) { + return AclMemory::aclrtMallocHost(hostPtr, size); + } + auto val = host_mem_fail_list_.front(); + host_mem_fail_list_.erase(host_mem_fail_list_.begin()); + if (val) { + return AclMemory::aclrtMallocHost(hostPtr, size); + } + return 1; + } + aclError acldvppMalloc(void **devPtr, size_t size) override { + if (dvpp_mem_fail_list_.empty()) { + return AclMemory::acldvppMalloc(devPtr, size); + } + auto val = dvpp_mem_fail_list_.front(); + dvpp_mem_fail_list_.erase(dvpp_mem_fail_list_.begin()); + if (val) { + return AclMemory::acldvppMalloc(devPtr, size); + } + return 1; + } + + std::vector device_mem_fail_list_; + std::vector host_mem_fail_list_; + std::vector dvpp_mem_fail_list_; +}; + +class AclSessionModelLoadTest : public AclSessionTest { + public: + AclSessionModelLoadTest() = default; + void SetUp() override { + AclSessionTest::SetUp(); + aclmdlDesc model_desc; + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + mock_model_desc_ = MockModelDesc(model_desc); + g_acl_model_desc = &mock_model_desc_; + g_acl_device_context_stream = &fail_acl_device_context_stream_; + g_acl_memory = &fail_acl_memory_; + } + void CreateDefaultRequest(PredictRequest &request) { + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + auto input1 = request.add_data(); + CreateTensor(*input1, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + + void CheckDefaultReply(const PredictReply &reply) { + EXPECT_TRUE(reply.result().size() == 2); + if (reply.result().size() == 2) { + CheckTensorItem(reply.result(0), {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + CheckTensorItem(reply.result(1), {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + } + MockModelDesc mock_model_desc_; + /* Test Resource will be release on something wrong happens*/ + MockFailAclDeviceContextStream fail_acl_device_context_stream_; + MockFailAclMemory fail_acl_memory_; +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_OneTime_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_SetDeviceFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.set_device_fail_list_.push_back(false); + EXPECT_FALSE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_CreateContextFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.create_context_fail_list_.push_back(false); + EXPECT_FALSE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_CreateStreamFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.create_stream_fail_list_.push_back(false); + EXPECT_FALSE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_ResetDeviceFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.reset_device_fail_list_.push_back(false); + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + acl_session.FinalizeEnv(); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_DestroyContextFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.destroy_context_fail_list_.push_back(false); + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + acl_session.FinalizeEnv(); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_DestroyStreamFail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + fail_acl_device_context_stream_.destroy_stream_fail_list_.push_back(false); + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + acl_session.FinalizeEnv(); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_MallocFail0_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.device_mem_fail_list_.push_back(false); // input0 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_MallocFail1_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.device_mem_fail_list_.push_back(true); // input0 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(false); // input1 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_MallocFail2_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.device_mem_fail_list_.push_back(true); // input0 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(true); // input1 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(false); // output0 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_MallocFail3_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.device_mem_fail_list_.push_back(true); // input0 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(true); // input1 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(true); // output0 buffer + fail_acl_memory_.device_mem_fail_list_.push_back(false); // output1 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_RunOnDevice_MallocFail0_Success) { + SetDeviceRunMode(); + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.host_mem_fail_list_.push_back(false); // output0 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionModelLoadTest, TestAclSession_RunOnDevice_MallocFail1_Success) { + SetDeviceRunMode(); + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + fail_acl_memory_.host_mem_fail_list_.push_back(true); // output0 buffer + fail_acl_memory_.host_mem_fail_list_.push_back(false); // output1 buffer + EXPECT_FALSE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +} // namespace serving +} // namespace mindspore \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_session_test_one_input_output.cc b/tests/ut/cpp/serving/acl_session_test_one_input_output.cc new file mode 100644 index 0000000000000000000000000000000000000000..0f04756f6b005b9bc210035c9e320095023a9fbf --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_one_input_output.cc @@ -0,0 +1,138 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_session_test_common.h" + +using namespace std; + +namespace mindspore { +namespace serving { + +class AclSessionOneInputOneOutputTest : public AclSessionTest { + public: + AclSessionOneInputOneOutputTest() = default; + void SetUp() override { + AclSessionTest::SetUp(); + aclmdlDesc model_desc; + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 8, 8, 3}, .data_type = ACL_FLOAT, .size = 2 * 8 * 8 * 3 * sizeof(float)}); + mock_model_desc_ = MockModelDesc(model_desc); + g_acl_model_desc = &mock_model_desc_; + } + void CreateDefaultRequest(PredictRequest &request) { + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + + void CreateInvalidDataSizeRequest(PredictRequest &request) { + auto input0 = request.add_data(); + // data size invalid, not match model input required + CreateTensor(*input0, {2, 24, 24, 2}, ::ms_serving::DataType::MS_FLOAT32); + } + + void CheckDefaultReply(const PredictReply &reply) { + EXPECT_TRUE(reply.result().size() == 1); + if (reply.result().size() == 1) { + CheckTensorItem(reply.result(0), {2, 8, 8, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + } + + MockModelDesc mock_model_desc_; +}; + +TEST_F(AclSessionOneInputOneOutputTest, TestAclSession_OneTime_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionOneInputOneOutputTest, TestAclSession_MutilTimes_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionOneInputOneOutputTest, TestAclSession_InvalidDataSize_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionOneInputOneOutputTest, TestAclSession_InvalidDataSize_MultiTimes_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +} // namespace serving +} // namespace mindspore \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_session_test_two_input_output.cc b/tests/ut/cpp/serving/acl_session_test_two_input_output.cc new file mode 100644 index 0000000000000000000000000000000000000000..08e150cb96743d39c259b66326e3235961fdfd70 --- /dev/null +++ b/tests/ut/cpp/serving/acl_session_test_two_input_output.cc @@ -0,0 +1,226 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_session_test_common.h" + +using namespace std; + +namespace mindspore { +namespace serving { + +class AclSessionTwoInputTwoOutputTest : public AclSessionTest { + public: + AclSessionTwoInputTwoOutputTest() = default; + void SetUp() override { + AclSessionTest::SetUp(); + aclmdlDesc model_desc; + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 24, 24, 3}, .data_type = ACL_FLOAT, .size = 2 * 24 * 24 * 3 * sizeof(float)}); + + model_desc.inputs.push_back( + AclTensorDesc{.dims = {2, 32}, .data_type = ACL_INT32, .size = 2 * 32 * sizeof(int32_t)}); + + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 8, 8, 3}, .data_type = ACL_FLOAT, .size = 2 * 8 * 8 * 3 * sizeof(float)}); + + model_desc.outputs.push_back( + AclTensorDesc{.dims = {2, 1024}, .data_type = ACL_BOOL, .size = 2 * 1024 * sizeof(bool)}); + + mock_model_desc_ = MockModelDesc(model_desc); + g_acl_model_desc = &mock_model_desc_; + } + void CreateDefaultRequest(PredictRequest &request) { + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + auto input1 = request.add_data(); + CreateTensor(*input1, {2, 32}, ::ms_serving::DataType::MS_INT32); + } + + void CreateInvalidDataSizeRequest0(PredictRequest &request) { + auto input0 = request.add_data(); + // data size invalid, not match model input required + CreateTensor(*input0, {2, 24, 24, 2}, ::ms_serving::DataType::MS_FLOAT32); + + auto input1 = request.add_data(); + CreateTensor(*input1, {2, 32}, ::ms_serving::DataType::MS_INT32); + } + + void CreateInvalidDataSizeRequest1(PredictRequest &request) { + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + auto input1 = request.add_data(); + // data size invalid, not match model input required + CreateTensor(*input1, {2, 16}, ::ms_serving::DataType::MS_INT32); + } + + void CreateInvalidDataSizeRequestOneInput0(PredictRequest &request) { + // only has one input for input0 + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 24, 24, 3}, ::ms_serving::DataType::MS_FLOAT32); + } + + void CreateInvalidDataSizeRequestOneInput1(PredictRequest &request) { + // only has one input for input1 + auto input0 = request.add_data(); + CreateTensor(*input0, {2, 32}, ::ms_serving::DataType::MS_INT32); + } + + void CheckDefaultReply(const PredictReply &reply) { + EXPECT_TRUE(reply.result().size() == 2); + if (reply.result().size() == 2) { + CheckTensorItem(reply.result(0), {2, 8, 8, 3}, ::ms_serving::DataType::MS_FLOAT32); + CheckTensorItem(reply.result(1), {2, 1024}, ::ms_serving::DataType::MS_BOOL); + } + } + + MockModelDesc mock_model_desc_; +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_OneTime_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_MutilTimes_Success) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateDefaultRequest(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_TRUE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + CheckDefaultReply(reply); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_Input0_InvalidDataSize_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequest0(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_Input1_InvalidDataSize_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequest1(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_OnlyInput0_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequestOneInput0(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_OnlyInput1_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequestOneInput1(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +TEST_F(AclSessionTwoInputTwoOutputTest, TestAclSession_InvalidDataSize_MultiTimes_Fail) { + inference::AclSession acl_session; + uint32_t device_id = 1; + EXPECT_TRUE(acl_session.InitEnv("Ascend", device_id) == SUCCESS); + uint32_t model_id = 0; + EXPECT_TRUE(acl_session.LoadModelFromFile("fake_model_path", model_id) == SUCCESS); + for (int i = 0; i < 10; i++) { + // create inputs + PredictRequest request; + CreateInvalidDataSizeRequest0(request); + + PredictReply reply; + ServingRequest serving_request(request); + ServingReply serving_reply(reply); + EXPECT_FALSE(acl_session.ExecuteModel(model_id, serving_request, serving_reply) == SUCCESS); + } + EXPECT_TRUE(acl_session.UnloadModel(model_id) == SUCCESS); + EXPECT_TRUE(acl_session.FinalizeEnv() == SUCCESS); +}; + +} // namespace serving +} // namespace mindspore \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_stub.cc b/tests/ut/cpp/serving/acl_stub.cc new file mode 100644 index 0000000000000000000000000000000000000000..f11829befd12312e8a08f053e164d3188e55a8bc --- /dev/null +++ b/tests/ut/cpp/serving/acl_stub.cc @@ -0,0 +1,323 @@ +/** + * Copyright 2020 Huawei Technologies 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 "acl_stub.h" +#include + +AclDataBuffer *g_acl_data_buffer = nullptr; +AclEnv *g_acl_env = nullptr; +AclDataSet *g_acl_dataset = nullptr; +AclModel *g_acl_model = nullptr; +AclModelDesc *g_acl_model_desc = nullptr; +AclDeviceContextStream *g_acl_device_context_stream = nullptr; +AclMemory *g_acl_memory = nullptr; +AclDvppPicDesc *g_acl_dvpp_pic_desc = nullptr; +AclDvppRoiConfig *g_acl_dvpp_roi_config = nullptr; +AclDvppResizeConfig *g_acl_dvpp_resize_config = nullptr; +AclDvppChannelDesc *g_acl_dvpp_channel_desc = nullptr; +AclDvppProcess *g_acl_dvpp_process = nullptr; +AclRunMode *g_acl_run_mode = nullptr; +AclJpegLib *g_acl_jpeg_lib = nullptr; + +aclDataBuffer *aclCreateDataBuffer(void *data, size_t size) { + return g_acl_data_buffer->aclCreateDataBuffer(data, size); +} + +aclError aclDestroyDataBuffer(const aclDataBuffer *dataBuffer) { + return g_acl_data_buffer->aclDestroyDataBuffer(dataBuffer); +} + +void *aclGetDataBufferAddr(const aclDataBuffer *dataBuffer) { + return g_acl_data_buffer->aclGetDataBufferAddr(dataBuffer); +} + +uint32_t aclGetDataBufferSize(const aclDataBuffer *dataBuffer) { + return g_acl_data_buffer->aclGetDataBufferSize(dataBuffer); +} + +size_t aclDataTypeSize(aclDataType dataType) { + std::unordered_map dataTypeMap = { + {ACL_FLOAT16, 2}, {ACL_FLOAT, 4}, {ACL_DOUBLE, 8}, {ACL_INT8, 1}, {ACL_INT16, 2}, {ACL_INT32, 4}, + {ACL_INT64, 8}, {ACL_UINT8, 1}, {ACL_UINT16, 2}, {ACL_UINT32, 4}, {ACL_UINT64, 8}, {ACL_BOOL, 1}, + }; + auto it = dataTypeMap.find(dataType); + if (it == dataTypeMap.end()) { + return 0; + } else { + return it->second; + } +} + +void aclAppLog(aclLogLevel logLevel, const char *func, const char *file, uint32_t line, const char *fmt, ...) { + if (logLevel == ACL_ERROR) { + // std::cout << file << ":" << line << "," << func << ": " << fmt << std::endl; + } +} + +aclError aclInit(const char *configPath) { return g_acl_env->aclInit(configPath); } + +aclError aclFinalize() { return g_acl_env->aclFinalize(); } + +// dataset +aclmdlDataset *aclmdlCreateDataset() { return g_acl_dataset->aclmdlCreateDataset(); } + +aclError aclmdlDestroyDataset(const aclmdlDataset *dataSet) { return g_acl_dataset->aclmdlDestroyDataset(dataSet); } + +aclError aclmdlAddDatasetBuffer(aclmdlDataset *dataSet, aclDataBuffer *dataBuffer) { + return g_acl_dataset->aclmdlAddDatasetBuffer(dataSet, dataBuffer); +} + +size_t aclmdlGetDatasetNumBuffers(const aclmdlDataset *dataSet) { + return g_acl_dataset->aclmdlGetDatasetNumBuffers(dataSet); +} + +aclDataBuffer *aclmdlGetDatasetBuffer(const aclmdlDataset *dataSet, size_t index) { + return g_acl_dataset->aclmdlGetDatasetBuffer(dataSet, index); +} + +// model +aclError aclmdlLoadFromFile(const char *modelPath, uint32_t *modelId) { + return g_acl_model->aclmdlLoadFromFile(modelPath, modelId); +} + +aclError aclmdlLoadFromMem(const void *model, size_t modelSize, uint32_t *modelId) { + return g_acl_model->aclmdlLoadFromMem(model, modelSize, modelId); +} + +aclError aclmdlLoadFromFileWithMem(const char *modelPath, uint32_t *modelId, void *workPtr, size_t workSize, + void *weightPtr, size_t weightSize) { + return g_acl_model->aclmdlLoadFromFileWithMem(modelPath, modelId, workPtr, workSize, weightPtr, weightSize); +} + +aclError aclmdlLoadFromMemWithMem(const void *model, size_t modelSize, uint32_t *modelId, void *workPtr, + size_t workSize, void *weightPtr, size_t weightSize) { + return g_acl_model->aclmdlLoadFromMemWithMem(model, modelSize, modelId, workPtr, workSize, weightPtr, weightSize); +} + +aclError aclmdlExecute(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output) { + return g_acl_model->aclmdlExecute(modelId, input, output); +} + +aclError aclmdlExecuteAsync(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output, aclrtStream stream) { + return g_acl_model->aclmdlExecuteAsync(modelId, input, output, stream); +} + +aclError aclmdlUnload(uint32_t modelId) { return g_acl_model->aclmdlUnload(modelId); } + +// model desc +aclmdlDesc *aclmdlCreateDesc() { return g_acl_model_desc->aclmdlCreateDesc(); } + +aclError aclmdlDestroyDesc(aclmdlDesc *modelDesc) { return g_acl_model_desc->aclmdlDestroyDesc(modelDesc); } + +aclError aclmdlGetDesc(aclmdlDesc *modelDesc, uint32_t modelId) { + return g_acl_model_desc->aclmdlGetDesc(modelDesc, modelId); +} + +size_t aclmdlGetNumInputs(aclmdlDesc *modelDesc) { return g_acl_model_desc->aclmdlGetNumInputs(modelDesc); } + +size_t aclmdlGetNumOutputs(aclmdlDesc *modelDesc) { return g_acl_model_desc->aclmdlGetNumOutputs(modelDesc); } + +size_t aclmdlGetInputSizeByIndex(aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetInputSizeByIndex(modelDesc, index); +} + +size_t aclmdlGetOutputSizeByIndex(aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetOutputSizeByIndex(modelDesc, index); +} + +aclError aclmdlGetInputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + return g_acl_model_desc->aclmdlGetInputDims(modelDesc, index, dims); +} + +aclError aclmdlGetOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + return g_acl_model_desc->aclmdlGetOutputDims(modelDesc, index, dims); +} + +aclError aclmdlGetCurOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + return g_acl_model_desc->aclmdlGetCurOutputDims(modelDesc, index, dims); +} + +aclFormat aclmdlGetInputFormat(const aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetInputFormat(modelDesc, index); +} + +aclFormat aclmdlGetOutputFormat(const aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetOutputFormat(modelDesc, index); +} + +aclDataType aclmdlGetInputDataType(const aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetInputDataType(modelDesc, index); +} + +aclDataType aclmdlGetOutputDataType(const aclmdlDesc *modelDesc, size_t index) { + return g_acl_model_desc->aclmdlGetOutputDataType(modelDesc, index); +} + +// device, context, stream + +aclError aclrtCreateContext(aclrtContext *context, int32_t deviceId) { + return g_acl_device_context_stream->aclrtCreateContext(context, deviceId); +} + +aclError aclrtDestroyContext(aclrtContext context) { return g_acl_device_context_stream->aclrtDestroyContext(context); } + +aclError aclrtSetCurrentContext(aclrtContext context) { + return g_acl_device_context_stream->aclrtSetCurrentContext(context); +} + +aclError aclrtSetDevice(int32_t deviceId) { return g_acl_device_context_stream->aclrtSetDevice(deviceId); } + +aclError aclrtResetDevice(int32_t deviceId) { return g_acl_device_context_stream->aclrtResetDevice(deviceId); } + +aclError aclrtGetRunMode(aclrtRunMode *runMode) { return g_acl_run_mode->aclrtGetRunMode(runMode); } + +aclError aclrtCreateStream(aclrtStream *stream) { return g_acl_device_context_stream->aclrtCreateStream(stream); } + +aclError aclrtDestroyStream(aclrtStream stream) { return g_acl_device_context_stream->aclrtDestroyStream(stream); } + +aclError aclrtSynchronizeStream(aclrtStream stream) { + return g_acl_device_context_stream->aclrtSynchronizeStream(stream); +} + +// memory +aclError acldvppMalloc(void **devPtr, size_t size) { return g_acl_memory->acldvppMalloc(devPtr, size); } +aclError acldvppFree(void *devPtr) { return g_acl_memory->acldvppFree(devPtr); } + +aclError aclrtMalloc(void **devPtr, size_t size, aclrtMemMallocPolicy policy) { + return g_acl_memory->aclrtMalloc(devPtr, size, policy); +} + +aclError aclrtFree(void *devPtr) { return g_acl_memory->aclrtFree(devPtr); } + +aclError aclrtMallocHost(void **hostPtr, size_t size) { return g_acl_memory->aclrtMallocHost(hostPtr, size); } + +aclError aclrtFreeHost(void *hostPtr) { return g_acl_memory->aclrtFreeHost(hostPtr); } + +aclError aclrtMemcpy(void *dst, size_t destMax, const void *src, size_t count, aclrtMemcpyKind kind) { + return g_acl_memory->aclrtMemcpy(dst, destMax, src, count, kind); +} + +acldvppPicDesc *acldvppCreatePicDesc() { return g_acl_dvpp_pic_desc->acldvppCreatePicDesc(); } +aclError acldvppDestroyPicDesc(acldvppPicDesc *picDesc) { return g_acl_dvpp_pic_desc->acldvppDestroyPicDesc(picDesc); } + +aclError acldvppSetPicDescSize(acldvppPicDesc *picDesc, uint32_t size) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescSize(picDesc, size); +} + +aclError acldvppSetPicDescFormat(acldvppPicDesc *picDesc, acldvppPixelFormat format) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescFormat(picDesc, format); +} + +aclError acldvppSetPicDescWidth(acldvppPicDesc *picDesc, uint32_t width) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescWidth(picDesc, width); +} + +aclError acldvppSetPicDescHeight(acldvppPicDesc *picDesc, uint32_t height) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescHeight(picDesc, height); +} + +aclError acldvppSetPicDescData(acldvppPicDesc *picDesc, void *dataDev) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescData(picDesc, dataDev); +} + +aclError acldvppSetPicDescWidthStride(acldvppPicDesc *picDesc, uint32_t widthStride) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescWidthStride(picDesc, widthStride); +} + +aclError acldvppSetPicDescHeightStride(acldvppPicDesc *picDesc, uint32_t heightStride) { + return g_acl_dvpp_pic_desc->acldvppSetPicDescHeightStride(picDesc, heightStride); +} + +acldvppRoiConfig *acldvppCreateRoiConfig(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { + return g_acl_dvpp_roi_config->acldvppCreateRoiConfig(left, right, top, bottom); +} + +aclError acldvppDestroyRoiConfig(acldvppRoiConfig *roiConfig) { + return g_acl_dvpp_roi_config->acldvppDestroyRoiConfig(roiConfig); +} + +aclError acldvppSetRoiConfig(acldvppRoiConfig *roiConfig, uint32_t left, uint32_t right, uint32_t top, + uint32_t bottom) { + return g_acl_dvpp_roi_config->acldvppSetRoiConfig(roiConfig, left, right, top, bottom); +} + +acldvppResizeConfig *acldvppCreateResizeConfig() { return g_acl_dvpp_resize_config->acldvppCreateResizeConfig(); } + +aclError acldvppDestroyResizeConfig(acldvppResizeConfig *resizeConfig) { + return g_acl_dvpp_resize_config->acldvppDestroyResizeConfig(resizeConfig); +} + +aclError acldvppCreateChannel(acldvppChannelDesc *channelDesc) { + return g_acl_dvpp_channel_desc->acldvppCreateChannel(channelDesc); +} + +aclError acldvppDestroyChannel(acldvppChannelDesc *channelDesc) { + return g_acl_dvpp_channel_desc->acldvppDestroyChannel(channelDesc); +} + +acldvppChannelDesc *acldvppCreateChannelDesc() { return g_acl_dvpp_channel_desc->acldvppCreateChannelDesc(); } + +aclError acldvppDestroyChannelDesc(acldvppChannelDesc *channelDesc) { + return g_acl_dvpp_channel_desc->acldvppDestroyChannelDesc(channelDesc); +} + +aclError acldvppVpcResizeAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppResizeConfig *resizeConfig, aclrtStream stream) { + return g_acl_dvpp_process->acldvppVpcResizeAsync(channelDesc, inputDesc, outputDesc, resizeConfig, stream); +} + +aclError acldvppVpcCropAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, acldvppPicDesc *outputDesc, + acldvppRoiConfig *cropArea, aclrtStream stream) { + return g_acl_dvpp_process->acldvppVpcCropAsync(channelDesc, inputDesc, outputDesc, cropArea, stream); +} + +aclError acldvppVpcCropAndPasteAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppRoiConfig *cropArea, + acldvppRoiConfig *pasteArea, aclrtStream stream) { + return g_acl_dvpp_process->acldvppVpcCropAndPasteAsync(channelDesc, inputDesc, outputDesc, cropArea, pasteArea, + stream); +} + +aclError acldvppVpcBatchCropAsync(acldvppChannelDesc *channelDesc, acldvppBatchPicDesc *srcBatchDesc, uint32_t *roiNums, + uint32_t size, acldvppBatchPicDesc *dstBatchDesc, acldvppRoiConfig *cropAreas[], + aclrtStream stream) { + return g_acl_dvpp_process->acldvppVpcBatchCropAsync(channelDesc, srcBatchDesc, roiNums, size, dstBatchDesc, cropAreas, + stream); +} + +aclError acldvppJpegDecodeAsync(acldvppChannelDesc *channelDesc, const void *data, uint32_t size, + acldvppPicDesc *outputDesc, aclrtStream stream) { + return g_acl_dvpp_process->acldvppJpegDecodeAsync(channelDesc, data, size, outputDesc, stream); +} + +// jpeg lib +void jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize) { + g_acl_jpeg_lib->jpeg_CreateDecompress(cinfo, version, structsize); +} + +void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, unsigned long insize) { + g_acl_jpeg_lib->jpeg_mem_src(cinfo, inbuffer, insize); +} + +int jpeg_read_header(j_decompress_ptr cinfo, boolean require_image) { + return g_acl_jpeg_lib->jpeg_read_header(cinfo, require_image); +} + +void jpeg_destroy_decompress(j_decompress_ptr cinfo) { g_acl_jpeg_lib->jpeg_destroy_decompress(cinfo); } + +struct jpeg_error_mgr *jpeg_std_error(struct jpeg_error_mgr *err) { + return err; +} \ No newline at end of file diff --git a/tests/ut/cpp/serving/acl_stub.h b/tests/ut/cpp/serving/acl_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..3113d27bfc13896dbe50069ed14cc7e1246e9f5a --- /dev/null +++ b/tests/ut/cpp/serving/acl_stub.h @@ -0,0 +1,857 @@ +/** + * Copyright 2020 Huawei Technologies 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 MINDSPORE_ACL_STUB_H +#define MINDSPORE_ACL_STUB_H + +#include "acl/acl_base.h" +#include "acl/acl.h" +#include "acl/acl_mdl.h" +#include "acl/acl_rt.h" +#include "acl/ops/acl_dvpp.h" +#include +#include +#include +#include +#include +#include +#include +#include "jpeglib.h" + +struct aclDataBuffer { + void *data = nullptr; + size_t size = 0; +}; + +struct aclmdlDataset { + std::vector data_buffers; +}; + +struct aclTensorDesc {}; + +struct AclTensorDesc { + std::vector dims; + aclDataType data_type = ACL_DT_UNDEFINED; + size_t size = 0; +}; + +struct aclmdlDesc { + std::vector inputs; + std::vector outputs; +}; + +struct acldvppPicDesc { + uint32_t size = 0; + acldvppPixelFormat format = PIXEL_FORMAT_YUV_400; + uint32_t width = 0; + uint32_t height = 0; + void *dataDev = nullptr; + uint32_t widthStride = 0; + uint32_t heightStride = 0; +}; + +struct acldvppRoiConfig { + uint32_t left = 0; + uint32_t right = 0; + uint32_t top = 0; + uint32_t bottom = 0; +}; + +struct acldvppResizeConfig { + uint32_t id; +}; + +struct acldvppChannelDesc { + bool channel_valid_flag = false; +}; + +class AclModel; +extern AclModel *g_acl_model; + +template +aclError AclItemOnDestroy( + std::vector &live, std::vector &destroy, const Type *destroy_item, + std::function func_release = [](Type &list_item) {}) { + for (auto it = live.begin(); it != live.end(); it++) { + if (&(*it) == destroy_item) { + func_release(*it); + destroy.push_back(*it); + live.erase(it); + return ACL_ERROR_NONE; + } + } + return 1; +} + +template ::value, int>::type = 0> +class ResourceBase { + public: + using Type = typename std::remove_pointer::type; + ResourceBase() = default; + virtual ~ResourceBase() { Clear(); } + void Clear() { + for (auto item : resource_live_) { + delete item; + } + resource_live_.clear(); + resource_destroy_.clear(); + } + template + Type *OnCreate(Args &&... args) { + auto item = new Type(std::forward(args)...); + resource_live_.push_back(item); + return item; + } + aclError OnDestroy( + const Type *item, std::function func_release = [](Type &list_item) {}) { + auto it = std::find(resource_live_.begin(), resource_live_.end(), item); + if (it == resource_live_.end()) { + return 1; + } + func_release(**it); // Type& + resource_destroy_.push_back(*it); // Type* + resource_live_.erase(it); + delete item; + return ACL_ERROR_NONE; + } + size_t LiveSize() const { return resource_live_.size(); } + bool Check() const { return resource_live_.empty(); } + std::vector resource_live_; + std::vector resource_destroy_; +}; + +class AclDataBuffer { + public: + AclDataBuffer() {} + virtual ~AclDataBuffer() { Clear(); } + virtual void Clear() { data_buffer_.Clear(); } + bool Check() { return data_buffer_.Check(); } + + virtual aclDataBuffer *aclCreateDataBuffer(void *data, size_t size) { + aclDataBuffer data_buffer; + data_buffer.data = data; + data_buffer.size = size; + return data_buffer_.OnCreate(data_buffer); + } + + virtual aclError aclDestroyDataBuffer(const aclDataBuffer *dataBuffer) { return data_buffer_.OnDestroy(dataBuffer); } + + virtual void *aclGetDataBufferAddr(const aclDataBuffer *dataBuffer) { + if (dataBuffer == nullptr) { + return nullptr; + } + return dataBuffer->data; + } + + virtual uint32_t aclGetDataBufferSize(const aclDataBuffer *dataBuffer) { + if (dataBuffer == nullptr) { + return 0; + } + return dataBuffer->size; + } + ResourceBase data_buffer_; +}; + +class AclDataSet { + public: + AclDataSet() {} + virtual ~AclDataSet() { Clear(); } + virtual void Clear() { dataset_.Clear(); } + bool Check() { return dataset_.Check(); } + + public: + virtual aclmdlDataset *aclmdlCreateDataset() { return dataset_.OnCreate(); } + virtual aclError aclmdlDestroyDataset(const aclmdlDataset *dataSet) { return dataset_.OnDestroy(dataSet); } + virtual aclError aclmdlAddDatasetBuffer(aclmdlDataset *dataSet, aclDataBuffer *dataBuffer) { + if (dataSet == nullptr) { + return 1; + } + dataSet->data_buffers.push_back(dataBuffer); + return ACL_ERROR_NONE; + } + virtual size_t aclmdlGetDatasetNumBuffers(const aclmdlDataset *dataSet) { + if (dataSet == nullptr) { + return 0; + } + return dataSet->data_buffers.size(); + } + virtual aclDataBuffer *aclmdlGetDatasetBuffer(const aclmdlDataset *dataSet, size_t index) { + if (dataSet == nullptr || index >= dataSet->data_buffers.size()) { + return nullptr; + } + return dataSet->data_buffers[index]; + } + ResourceBase dataset_; +}; + +class AclEnv { + public: + virtual aclError aclInit(const char *configPath) { + is_init = true; + return ACL_ERROR_NONE; + } + virtual aclError aclFinalize() { + is_init = false; + return ACL_ERROR_NONE; + } + bool Check() { return is_init == false; } + bool is_init = false; +}; + +class AclModel { + public: + bool Check() { return model_live_.empty(); } + virtual aclError aclmdlLoadFromFile(const char *modelPath, uint32_t *modelId) { + model_live_.push_back(cur_max_model_id_); + *modelId = cur_max_model_id_; + cur_max_model_id_++; + return ACL_ERROR_NONE; + } + + virtual aclError aclmdlLoadFromMem(const void *model, size_t modelSize, uint32_t *modelId) { + return aclmdlLoadFromFile("fake_path", modelId); + } + + virtual aclError aclmdlLoadFromFileWithMem(const char *modelPath, uint32_t *modelId, void *workPtr, size_t workSize, + void *weightPtr, size_t weightSize) { + return aclmdlLoadFromFile(modelPath, modelId); + } + + virtual aclError aclmdlLoadFromMemWithMem(const void *model, size_t modelSize, uint32_t *modelId, void *workPtr, + size_t workSize, void *weightPtr, size_t weightSize) { + return aclmdlLoadFromMem(model, modelSize, modelId); + } + + virtual aclError aclmdlExecute(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output) { + if (std::find(model_live_.begin(), model_live_.end(), modelId) == model_live_.end()) { + return 1; + } + if (input == nullptr || output == nullptr) { + return false; + } + // auto& model_desc = model_live_[modelId]; + return ACL_ERROR_NONE; + } + + virtual aclError aclmdlExecuteAsync(uint32_t modelId, const aclmdlDataset *input, aclmdlDataset *output, + aclrtStream stream) { + return ACL_ERROR_NONE; + } + + virtual aclError aclmdlUnload(uint32_t modelId) { + auto it = std::find(model_live_.begin(), model_live_.end(), modelId); + if (it == model_live_.end()) { + return 1; + } + model_live_.erase(it); + model_destroy_.push_back(modelId); + return ACL_ERROR_NONE; + } + uint32_t cur_max_model_id_ = 0; + std::vector model_live_; + std::vector model_destroy_; +}; + +class AclModelDesc { + public: + AclModelDesc() {} + virtual ~AclModelDesc() { Clear(); } + virtual void Clear() { model_desc_.Clear(); } + bool Check() { return model_desc_.Check(); } + + public: + virtual aclmdlDesc *aclmdlCreateDesc() { return model_desc_.OnCreate(); } + aclError aclmdlDestroyDesc(aclmdlDesc *modelDesc) { return model_desc_.OnDestroy(modelDesc); } + + aclError aclmdlGetDesc(aclmdlDesc *modelDesc, uint32_t modelId) { + auto &model_live = g_acl_model->model_live_; + auto it = std::find(model_live.begin(), model_live.end(), modelId); + if (it == model_live.end()) { + return 1; + } + return ACL_ERROR_NONE; + } + + size_t aclmdlGetNumInputs(aclmdlDesc *modelDesc) { return modelDesc->inputs.size(); } + + size_t aclmdlGetNumOutputs(aclmdlDesc *modelDesc) { return modelDesc->outputs.size(); } + + size_t aclmdlGetInputSizeByIndex(aclmdlDesc *modelDesc, size_t index) { return modelDesc->inputs[index].size; } + + size_t aclmdlGetOutputSizeByIndex(aclmdlDesc *modelDesc, size_t index) { return modelDesc->outputs[index].size; } + + aclError aclmdlGetInputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + auto &input = modelDesc->inputs[index]; + dims->dimCount = input.dims.size(); + for (size_t i = 0; i < dims->dimCount; i++) { + dims->dims[i] = input.dims[i]; + } + return ACL_ERROR_NONE; + } + + aclError aclmdlGetOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + auto &input = modelDesc->outputs[index]; + dims->dimCount = input.dims.size(); + for (size_t i = 0; i < dims->dimCount; i++) { + dims->dims[i] = input.dims[i]; + } + return ACL_ERROR_NONE; + } + + aclError aclmdlGetCurOutputDims(const aclmdlDesc *modelDesc, size_t index, aclmdlIODims *dims) { + return aclmdlGetOutputDims(modelDesc, index, dims); + } + + aclFormat aclmdlGetInputFormat(const aclmdlDesc *modelDesc, size_t index) { return ACL_FORMAT_NCHW; } + aclFormat aclmdlGetOutputFormat(const aclmdlDesc *modelDesc, size_t index) { return ACL_FORMAT_NCHW; } + + aclDataType aclmdlGetInputDataType(const aclmdlDesc *modelDesc, size_t index) { + return modelDesc->inputs[index].data_type; + } + + aclDataType aclmdlGetOutputDataType(const aclmdlDesc *modelDesc, size_t index) { + return modelDesc->outputs[index].data_type; + } + + ResourceBase model_desc_; +}; + +class AclRunMode { + public: + virtual aclError aclrtGetRunMode(aclrtRunMode *runMode) { + *runMode = aclrtRunMode::ACL_HOST; + return ACL_ERROR_NONE; + } +}; + +class AclDeviceContextStream { + public: + AclDeviceContextStream() {} + ~AclDeviceContextStream() { Clear(); } + virtual void Clear() { + for (auto context : context_live_) { + delete (int *)context; + } + context_live_.clear(); + context_destroy_.clear(); + device_id_live_.clear(); + device_id_destroy_.clear(); + for (auto item : stream_live_) { + delete (int *)item; + } + stream_live_.clear(); + stream_destroy_.clear(); + } + bool Check() { return context_live_.empty() && device_id_live_.empty() && stream_live_.empty(); } + virtual aclError aclrtCreateContext(aclrtContext *context, int32_t deviceId) { + context_live_.push_back(new int()); + *context = context_live_.back(); + return ACL_ERROR_NONE; + } + virtual aclError aclrtDestroyContext(aclrtContext context) { + for (auto it = context_live_.begin(); it != context_live_.end(); ++it) { + if (*it == context) { + context_live_.erase(it); + context_destroy_.push_back(context); + delete (int *)context; + return ACL_ERROR_NONE; + } + } + return 1; + } + aclError aclrtSetCurrentContext(aclrtContext context) { return ACL_ERROR_NONE; } + aclError aclrtGetCurrentContext(aclrtContext *context) { return ACL_ERROR_NONE; } + virtual aclError aclrtSetDevice(int32_t deviceId) { + device_id_live_.push_back(deviceId); + return ACL_ERROR_NONE; + } + virtual aclError aclrtResetDevice(int32_t deviceId) { + for (auto it = device_id_live_.begin(); it != device_id_live_.end(); ++it) { + if (*it == deviceId) { + device_id_live_.erase(it); + device_id_destroy_.push_back(deviceId); + return ACL_ERROR_NONE; + } + } + return 1; + } + aclError aclrtGetDevice(int32_t *deviceId) { + *deviceId = 0; + return ACL_ERROR_NONE; + } + aclError aclrtSynchronizeDevice(void) { return ACL_ERROR_NONE; } + aclError aclrtSetTsDevice(aclrtTsId tsId) { return ACL_ERROR_NONE; } + aclError aclrtGetDeviceCount(uint32_t *count) { + *count = 1; + return ACL_ERROR_NONE; + } + virtual aclError aclrtCreateStream(aclrtStream *stream) { + stream_live_.push_back(new int()); + *stream = stream_live_.back(); + return ACL_ERROR_NONE; + } + virtual aclError aclrtDestroyStream(aclrtStream stream) { + for (auto it = stream_live_.begin(); it != context_live_.end(); ++it) { + if (*it == stream) { + stream_live_.erase(it); + stream_destroy_.push_back(stream); + delete (int *)stream; + return ACL_ERROR_NONE; + } + } + return 1; + } + aclError aclrtSynchronizeStream(aclrtStream stream) { + for (auto it = stream_live_.begin(); it != context_live_.end(); ++it) { + if (*it == stream) { + return ACL_ERROR_NONE; + } + } + return 1; + } + std::vector device_id_live_; + std::vector device_id_destroy_; + std::vector context_live_; + std::vector context_destroy_; + std::vector stream_live_; + std::vector stream_destroy_; +}; + +class AclMemory { + public: + AclMemory() {} + ~AclMemory() { Clear(); } + void Clear() { + for (auto item : device_buffer_live_) { + delete[] item; + } + for (auto item : host_buffer_live_) { + delete[] item; + } + for (auto item : dvpp_buffer_live_) { + delete[] item; + } + device_buffer_live_.clear(); + device_buffer_destroy_.clear(); + host_buffer_live_.clear(); + host_buffer_destroy_.clear(); + dvpp_buffer_live_.clear(); + dvpp_buffer_destroy_.clear(); + } + bool Check() { return device_buffer_live_.empty() && host_buffer_live_.empty() && dvpp_buffer_live_.empty(); } + virtual aclError aclrtMalloc(void **devPtr, size_t size, aclrtMemMallocPolicy policy) { + auto buffer = new uint8_t[size]; + *devPtr = buffer; + device_buffer_live_.push_back(buffer); + memory_len_[buffer] = size; + return ACL_ERROR_NONE; + } + aclError aclrtFree(void *devPtr) { + auto it = std::find(device_buffer_live_.begin(), device_buffer_live_.end(), devPtr); + if (it != device_buffer_live_.end()) { + delete[](*it); + device_buffer_live_.erase(it); + device_buffer_destroy_.push_back(*it); + return ACL_ERROR_NONE; + } + return 1; + } + + virtual aclError aclrtMallocHost(void **hostPtr, size_t size) { + auto buffer = new uint8_t[size]; + *hostPtr = buffer; + host_buffer_live_.push_back(buffer); + memory_len_[buffer] = size; + return ACL_ERROR_NONE; + } + + aclError aclrtFreeHost(void *hostPtr) { + auto it = std::find(host_buffer_live_.begin(), host_buffer_live_.end(), hostPtr); + if (it != host_buffer_live_.end()) { + delete[](*it); + host_buffer_live_.erase(it); + host_buffer_destroy_.push_back(*it); + return ACL_ERROR_NONE; + } + return 1; + } + + aclError aclrtMemcpy(void *dst, size_t destMax, const void *src, size_t count, aclrtMemcpyKind kind) { + auto is_device_memory = [this](const void *memory, uint32_t use_size) { + for (auto it = device_buffer_live_.begin(); it != device_buffer_live_.end(); it++) { + auto size = memory_len_[*it]; + if (memory >= *it && static_cast(memory) + use_size <= (*it) + size) { + return true; + } + } + for (auto it = dvpp_buffer_live_.begin(); it != dvpp_buffer_live_.end(); it++) { + auto size = memory_len_[*it]; + if (memory >= *it && static_cast(memory) + use_size <= (*it) + size) { + return true; + } + } + return false; + }; + if (kind == ACL_MEMCPY_HOST_TO_HOST) { + if (is_device_memory(dst, destMax) || is_device_memory(src, count)) { + return 1; + } + } else if (kind == ACL_MEMCPY_HOST_TO_DEVICE) { + if (!is_device_memory(dst, destMax) || is_device_memory(src, count)) { + return 1; + } + } else if (kind == ACL_MEMCPY_DEVICE_TO_HOST) { + if (is_device_memory(dst, destMax) || !is_device_memory(src, count)) { + return 1; + } + } else if (kind == ACL_MEMCPY_DEVICE_TO_DEVICE) { + if (!is_device_memory(dst, destMax) || !is_device_memory(src, count)) { + return 1; + } + } else { + return 1; + } + memcpy(dst, src, count); + return ACL_ERROR_NONE; + } + + virtual aclError acldvppMalloc(void **devPtr, size_t size) { + auto buffer = new uint8_t[size]; + *devPtr = buffer; + dvpp_buffer_live_.push_back(buffer); + memory_len_[buffer] = size; + return ACL_ERROR_NONE; + } + aclError acldvppFree(void *devPtr) { + auto it = std::find(dvpp_buffer_live_.begin(), dvpp_buffer_live_.end(), devPtr); + if (it != dvpp_buffer_live_.end()) { + delete[](*it); + dvpp_buffer_live_.erase(it); + dvpp_buffer_destroy_.push_back(*it); + return ACL_ERROR_NONE; + } + return 1; + } + + std::vector device_buffer_live_; + std::vector device_buffer_destroy_; + std::vector host_buffer_live_; + std::vector host_buffer_destroy_; + std::vector dvpp_buffer_live_; + std::vector dvpp_buffer_destroy_; + std::map memory_len_; +}; + +class AclDvppPicDesc { + public: + bool Check() { return pic_desc_.Check(); } + acldvppPicDesc *acldvppCreatePicDesc() { return pic_desc_.OnCreate(); } + + aclError acldvppDestroyPicDesc(acldvppPicDesc *picDesc) { return pic_desc_.OnDestroy(picDesc); } + + aclError acldvppSetPicDescSize(acldvppPicDesc *picDesc, uint32_t size) { + picDesc->size = size; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescFormat(acldvppPicDesc *picDesc, acldvppPixelFormat format) { + picDesc->format = format; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescWidth(acldvppPicDesc *picDesc, uint32_t width) { + picDesc->width = width; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescHeight(acldvppPicDesc *picDesc, uint32_t height) { + picDesc->height = height; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescData(acldvppPicDesc *picDesc, void *dataDev) { + picDesc->dataDev = dataDev; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescWidthStride(acldvppPicDesc *picDesc, uint32_t widthStride) { + picDesc->widthStride = widthStride; + return ACL_ERROR_NONE; + } + + aclError acldvppSetPicDescHeightStride(acldvppPicDesc *picDesc, uint32_t heightStride) { + picDesc->heightStride = heightStride; + return ACL_ERROR_NONE; + } + ResourceBase pic_desc_; +}; + +class AclDvppRoiConfig { + public: + bool Check() { return roi_config_.Check(); } + acldvppRoiConfig *acldvppCreateRoiConfig(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { + return roi_config_.OnCreate(acldvppRoiConfig{.left = left, .right = right, .top = top, .bottom = bottom}); + } + + aclError acldvppDestroyRoiConfig(acldvppRoiConfig *roiConfig) { return roi_config_.OnDestroy(roiConfig); } + + aclError acldvppSetRoiConfig(acldvppRoiConfig *roiConfig, uint32_t left, uint32_t right, uint32_t top, + uint32_t bottom) { + roiConfig->left = left; + roiConfig->right = right; + roiConfig->top = top; + roiConfig->bottom = bottom; + return ACL_ERROR_NONE; + } + ResourceBase roi_config_; +}; + +class AclDvppResizeConfig { + public: + bool Check() { return resize_config_.Check(); } + acldvppResizeConfig *acldvppCreateResizeConfig() { return resize_config_.OnCreate(acldvppResizeConfig{}); } + + aclError acldvppDestroyResizeConfig(acldvppResizeConfig *resizeConfig) { + return resize_config_.OnDestroy(resizeConfig); + } + ResourceBase resize_config_; +}; + +class AclDvppChannelDesc { + public: + bool Check() { return channel_desc_.Check(); } + aclError acldvppCreateChannel(acldvppChannelDesc *channelDesc) { + channelDesc->channel_valid_flag = true; + return ACL_ERROR_NONE; + } + aclError acldvppDestroyChannel(acldvppChannelDesc *channelDesc) { + channelDesc->channel_valid_flag = false; + return ACL_ERROR_NONE; + } + acldvppChannelDesc *acldvppCreateChannelDesc() { return channel_desc_.OnCreate(); } + aclError acldvppDestroyChannelDesc(acldvppChannelDesc *channelDesc) { + if (channelDesc->channel_valid_flag) { + return 1; + } + return channel_desc_.OnDestroy(channelDesc); + } + ResourceBase channel_desc_; +}; + +class AclDvppProcess { + public: + bool Check() { return true; } + virtual aclError acldvppVpcResizeAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppResizeConfig *resizeConfig, + aclrtStream stream) { + resize_call_times_++; + if (channelDesc == nullptr || inputDesc == nullptr || outputDesc == nullptr || resizeConfig == nullptr || + stream == nullptr) { + return 1; + } + if (CheckPicDesc(inputDesc) != ACL_ERROR_NONE) { + return 1; + } + if (CheckPicDesc(outputDesc) != ACL_ERROR_NONE) { + return 1; + } + return ACL_ERROR_NONE; + } + + virtual aclError acldvppVpcCropAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppRoiConfig *cropArea, aclrtStream stream) { + crop_call_times_++; + if (channelDesc == nullptr || inputDesc == nullptr || outputDesc == nullptr || cropArea == nullptr || + stream == nullptr) { + return 1; + } + if (CheckPicDesc(inputDesc) != ACL_ERROR_NONE) { + return 1; + } + if (CheckPicDesc(outputDesc) != ACL_ERROR_NONE) { + return 1; + } + if (CheckCropArea(cropArea) != ACL_ERROR_NONE) { + return 1; + } + return ACL_ERROR_NONE; + } + + virtual aclError acldvppVpcCropAndPasteAsync(acldvppChannelDesc *channelDesc, acldvppPicDesc *inputDesc, + acldvppPicDesc *outputDesc, acldvppRoiConfig *cropArea, + acldvppRoiConfig *pasteArea, aclrtStream stream) { + crop_paste_call_times_++; + if (channelDesc == nullptr || inputDesc == nullptr || outputDesc == nullptr || cropArea == nullptr || + pasteArea == nullptr || stream == nullptr) { + return 1; + } + if (CheckPicDesc(inputDesc) != ACL_ERROR_NONE) { + return 1; + } + if (CheckPicDesc(outputDesc) != ACL_ERROR_NONE) { + return 1; + } + if (CheckCropArea(cropArea) != ACL_ERROR_NONE) { + return 1; + } + if (CheckCropArea(pasteArea) != ACL_ERROR_NONE) { + return 1; + } + return ACL_ERROR_NONE; + } + + aclError acldvppVpcBatchCropAsync(acldvppChannelDesc *channelDesc, acldvppBatchPicDesc *srcBatchDesc, + uint32_t *roiNums, uint32_t size, acldvppBatchPicDesc *dstBatchDesc, + acldvppRoiConfig *cropAreas[], aclrtStream stream) { + return ACL_ERROR_NONE; + } + + virtual aclError acldvppJpegDecodeAsync(acldvppChannelDesc *channelDesc, const void *data, uint32_t size, + acldvppPicDesc *outputDesc, aclrtStream stream) { + decode_call_times_++; + if (channelDesc == nullptr || data == nullptr || size == 0 || outputDesc == nullptr || stream == nullptr) { + return 1; + } + if (outputDesc->widthStride % 128 != 0) { + return 1; + } + if (outputDesc->heightStride % 16 != 0) { + return 1; + } + if (outputDesc->widthStride < 32 || outputDesc->widthStride > 8192) { + return 1; + } + if (outputDesc->heightStride < 32 || outputDesc->heightStride > 8192) { + return 1; + } + if (CheckPicDesc(outputDesc) != ACL_ERROR_NONE) { + return 1; + } + return ACL_ERROR_NONE; + } + aclError CheckCropArea(acldvppRoiConfig *crop_area) { + if (crop_area->left % 2 != 0 || crop_area->top % 2 != 0) { + return 1; + } + if (crop_area->right % 2 != 1 || crop_area->bottom % 2 != 1) { + return 1; + } + auto crop_width = crop_area->right - crop_area->left + 1; + if (crop_width < 10 || crop_width > 4096) { + return 1; + } + auto crop_heigth = crop_area->bottom - crop_area->top + 1; + if (crop_heigth < 6 || crop_heigth > 4096) { + return 1; + } + return ACL_ERROR_NONE; + } + aclError CheckPicDesc(acldvppPicDesc *pic_desc) { + if (pic_desc->width == 0 || pic_desc->height == 0) { + return 1; + } + if (pic_desc->widthStride % 16 != 0 || pic_desc->widthStride < pic_desc->width) { + return 1; + } + if (pic_desc->heightStride % 2 != 0 || pic_desc->heightStride < pic_desc->height) { + return 1; + } + if (pic_desc->widthStride < 32 || pic_desc->widthStride > 4096) { + return 1; + } + if (pic_desc->heightStride < 6 || pic_desc->heightStride > 4096) { + return 1; + } + if (pic_desc->dataDev == nullptr) { + return 1; + } + auto size = pic_desc->size; + auto ele_cnt = pic_desc->widthStride * pic_desc->heightStride; + switch (pic_desc->format) { + case PIXEL_FORMAT_YUV_SEMIPLANAR_420: + case PIXEL_FORMAT_YVU_SEMIPLANAR_420: + if (ele_cnt * 3 / 2 != size) { + return 1; + } + break; + case PIXEL_FORMAT_YUV_SEMIPLANAR_422: + case PIXEL_FORMAT_YVU_SEMIPLANAR_422: + if (ele_cnt * 2 != size) { + return 1; + } + break; + case PIXEL_FORMAT_YUV_SEMIPLANAR_444: + case PIXEL_FORMAT_YVU_SEMIPLANAR_444: + if (ele_cnt * 3 != size) { + return 1; + } + break; + default: + return 1; + } + return ACL_ERROR_NONE; + } + uint32_t decode_call_times_ = 0; + uint32_t resize_call_times_ = 0; + uint32_t crop_call_times_ = 0; + uint32_t crop_paste_call_times_ = 0; +}; + +class AclJpegLib { + public: + bool Check() { return jpeg_live_.empty(); } + AclJpegLib(uint32_t width, uint32_t height) : image_width_(width), image_height_(height) {} + + void jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize) { jpeg_live_.push_back(cinfo); } + void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, unsigned long insize) {} + int jpeg_read_header(j_decompress_ptr cinfo, boolean require_image) { + static JHUFF_TBL tal; + cinfo->image_width = image_width_; + cinfo->image_height = image_height_; + cinfo->jpeg_color_space = color_space_; + for (int i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->ac_huff_tbl_ptrs[i] = &tal; + cinfo->dc_huff_tbl_ptrs[i] = &tal; + } + return 0; + } + void jpeg_destroy_decompress(j_decompress_ptr cinfo) { + auto it = std::find(jpeg_live_.begin(), jpeg_live_.end(), cinfo); + if (it != jpeg_live_.end()) { + jpeg_live_.erase(it); + } + } + uint32_t image_width_; + uint32_t image_height_; + J_COLOR_SPACE color_space_ = JCS_YCbCr; + std::vector jpeg_live_; +}; + +extern AclDataBuffer *g_acl_data_buffer; +extern AclEnv *g_acl_env; +extern AclDataSet *g_acl_dataset; +extern AclModelDesc *g_acl_model_desc; +extern AclDeviceContextStream *g_acl_device_context_stream; +extern AclMemory *g_acl_memory; +extern AclDvppPicDesc *g_acl_dvpp_pic_desc; +extern AclDvppRoiConfig *g_acl_dvpp_roi_config; +extern AclDvppResizeConfig *g_acl_dvpp_resize_config; +extern AclDvppChannelDesc *g_acl_dvpp_channel_desc; +extern AclDvppProcess *g_acl_dvpp_process; +extern AclRunMode *g_acl_run_mode; +extern AclJpegLib *g_acl_jpeg_lib; + +#endif // MINDSPORE_ACL_STUB_H diff --git a/tests/ut/cpp/serving/ms_service.proto b/tests/ut/cpp/serving/ms_service.proto new file mode 120000 index 0000000000000000000000000000000000000000..dd846c368f94bbe87cff76bac171976c97987424 --- /dev/null +++ b/tests/ut/cpp/serving/ms_service.proto @@ -0,0 +1 @@ +../../../../serving/ms_service.proto \ No newline at end of file