/** * Copyright 2019-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 "graph/load/new_model_manager/model_manager.h" #include #include "common/l2_cache_optimize.h" #include "common/profiling/profiling_manager.h" #include "common/properties_manager.h" #include "framework/common/debug/ge_log.h" #include "graph/debug/ge_attr_define.h" #include "framework/common/util.h" #include "graph/load/new_model_manager/davinci_model.h" #include "graph/load/new_model_manager/davinci_model_parser.h" #include "model/ge_root_model.h" namespace ge { thread_local uint32_t device_count = 0; namespace { const int kCmdParSize = 2; const int kDumpCmdPairSize = 2; const char *const kNeedDestroySpecifiedAicpuKernel = "need_destroy_specified_aicpu_kernel"; } // namespace std::shared_ptr ModelManager::GetInstance() { static const std::shared_ptr instance_ptr = shared_ptr(new (std::nothrow) ModelManager(), ModelManager::FinalizeForPtr); return instance_ptr; } ModelManager::ModelManager() { max_model_id_ = 0; session_id_bias_ = 0; } Status ModelManager::KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType op_type, uint64_t session_id, uint32_t model_id) { STR_FWK_OP_KERNEL param_base = {}; void *devicebase = nullptr; void *aicpu_kernel_addr = nullptr; const uint32_t kKernelType = 0; param_base.fwkKernelType = kKernelType; param_base.fwkKernelBase.fwk_kernel.opType = op_type; param_base.fwkKernelBase.fwk_kernel.sessionID = session_id; if (op_type == aicpu::FWKAdapter::FWKOperateType::FWK_ADPT_KERNEL_DESTROY) { std::vector v_aicpu_kernel; std::string model_key = std::to_string(session_id) + "_" + std::to_string(model_id); auto iter = model_aicpu_kernel_.find(model_key); if (iter != model_aicpu_kernel_.end()) { GELOGD("kernel destroy session_id %lu, model_id %u.", session_id, model_id); v_aicpu_kernel = model_aicpu_kernel_.at(model_key); // Insert size of aicpu kernel vector in the first element v_aicpu_kernel.insert(v_aicpu_kernel.begin(), v_aicpu_kernel.size()); auto kernel_size = sizeof(uint64_t) * (v_aicpu_kernel.size()); rtError_t rt_ret = rtMalloc(&aicpu_kernel_addr, kernel_size, RT_MEMORY_HBM); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); return RT_FAILED;) rt_ret = rtMemcpy(aicpu_kernel_addr, kernel_size, v_aicpu_kernel.data(), kernel_size, RT_MEMCPY_HOST_TO_DEVICE); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy to input_output_addr_ error: 0x%X", rt_ret); GE_CHK_RT(rtFree(aicpu_kernel_addr)); return FAILED;) uint64_t kernel_id_addr = static_cast(reinterpret_cast(aicpu_kernel_addr)); param_base.fwkKernelBase.fwk_kernel.kernelID = kernel_id_addr; // In the scene of loading once and running many times, the kernel needs to be destroyed many times, // and connot be removed from kernel map. } } rtError_t rt_ret = rtMalloc(&(devicebase), sizeof(STR_FWK_OP_KERNEL), RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "malloc device memory failed."); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); return FAILED; } rt_ret = rtMemcpy(devicebase, sizeof(STR_FWK_OP_KERNEL), ¶m_base, sizeof(STR_FWK_OP_KERNEL), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "memory copy to device failed."); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); return FAILED; } rtStream_t stream = nullptr; rt_ret = rtStreamCreate(&stream, 0); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "create stream failed."); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); return FAILED; } rt_ret = rtKernelLaunchEx(devicebase, sizeof(STR_FWK_OP_KERNEL), 0, stream); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "rtKernelLaunchEx failed."); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); return FAILED; } rt_ret = rtStreamSynchronize(stream); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "rtStreamSynchronize failed."); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); return FAILED; } if (aicpu_kernel_addr != nullptr) { rt_ret = rtFree(aicpu_kernel_addr); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "free memory failed."); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); return FAILED; } } rt_ret = rtFree(devicebase); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "free memory failed."); GE_CHK_RT(rtStreamDestroy(stream)); return FAILED; } rt_ret = rtStreamDestroy(stream); if (rt_ret != RT_ERROR_NONE) { GELOGE(rt_ret, "rtStreamDestroy failed."); return FAILED; } return SUCCESS; } void ModelManager::DestroyAicpuSession(uint64_t session_id) { std::lock_guard lock(sess_ids_mutex_); auto it = sess_ids_.find(session_id); if (it == sess_ids_.end()) { GELOGI("The session: %lu not created.", session_id); return; } else { Status ret = KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType::FWK_ADPT_SESSION_DESTROY, session_id, 0); if (ret != SUCCESS) { GELOGW("The session: %lu destroy failed.", session_id); } else { (void)sess_ids_.erase(session_id); GELOGI("The session: %lu destroyed.", session_id); } } } ge::Status ModelManager::DestroyAicpuSessionForInfer(uint32_t model_id) { GELOGI("Destroy aicpu session for infer, model id is %u.", model_id); std::lock_guard lock(map_mutex_); auto it = model_map_.find(model_id); if (it == model_map_.end()) { GELOGE(PARAM_INVALID, "model id %u does not exists.", model_id); return PARAM_INVALID; } uint64_t session_id = it->second->GetSessionId(); GELOGI("Destroy aicpu session for infer, session id is %u.", session_id); DestroyAicpuSession(session_id); return SUCCESS; } ge::Status ModelManager::DestroyAicpuKernel(uint64_t session_id, uint32_t model_id) { GELOGD("destroy aicpu kernel in session_id %lu, model_id %u.", session_id, model_id); std::lock_guard lock(sess_ids_mutex_); std::string model_key = std::to_string(session_id) + "_" + std::to_string(model_id); if (model_aicpu_kernel_.find(model_key) != model_aicpu_kernel_.end()) { Status ret = KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType::FWK_ADPT_KERNEL_DESTROY, session_id, model_id); if (ret != SUCCESS) { GELOGE(FAILED, "Destroy aicpu kernel failed."); return FAILED; } } return SUCCESS; } ge::Status ModelManager::CreateAicpuKernel(uint64_t session_id, uint32_t model_id, uint64_t kernel_id) { std::lock_guard lock(sess_ids_mutex_); std::vector v_aicpu_kernel; std::string model_key = std::to_string(session_id) + "_" + std::to_string(model_id); if (model_aicpu_kernel_.find(model_key) != model_aicpu_kernel_.end()) { v_aicpu_kernel = model_aicpu_kernel_.at(model_key); } v_aicpu_kernel.push_back(kernel_id); model_aicpu_kernel_[model_key] = v_aicpu_kernel; return SUCCESS; } ModelManager::~ModelManager() { std::lock_guard lock(map_mutex_); model_map_.clear(); model_aicpu_kernel_.clear(); GE_IF_BOOL_EXEC(device_count > 0, GE_CHK_RT(rtDeviceReset(0))); } /// /// @ingroup domi_ome /// @brief set Device. If no device available, return failure /// @return Status run result /// @author /// Status ModelManager::SetDevice(int32_t deviceId) const { GE_CHK_RT_RET(rtSetDevice(deviceId)); return SUCCESS; } ge::Status ModelManager::SetDynamicSize(uint32_t model_id, const std::vector &batch_num) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHECK_NOTNULL(davinci_model); davinci_model->SetDynamicSize(batch_num); return SUCCESS; } ge::Status ModelManager::DoLoadHybridModelOnline(uint32_t model_id, const shared_ptr &ge_root_model, const shared_ptr &listener) { auto hybrid_model = hybrid::HybridDavinciModel::Create(ge_root_model); GE_CHECK_NOTNULL(hybrid_model); hybrid_model->SetListener(listener); hybrid_model->SetModelId(model_id); hybrid_model->SetDeviceId(GetContext().DeviceId()); GE_CHK_STATUS_RET(hybrid_model->Init(), "Failed to init hybrid model. model_id = %u", model_id); auto shared_model = std::shared_ptr(hybrid_model.release()); InsertModel(model_id, shared_model); return SUCCESS; } /// /// @ingroup domi_ome /// @brief load model online /// @return Status run result /// Status ModelManager::LoadModelOnline(uint32_t &model_id, const shared_ptr &ge_root_model, std::shared_ptr listener) { GE_CHK_BOOL_RET_STATUS(listener.get() != nullptr, PARAM_INVALID, "Param incorrect, listener is null"); if (model_id == INVALID_MODEL_ID) { GenModelId(&model_id); } bool is_shape_unknown = false; GE_CHK_STATUS_RET(ge_root_model->CheckIsUnknownShape(is_shape_unknown), "CheckIsUnknownShape failed, model id:%u", model_id); if (is_shape_unknown) { return DoLoadHybridModelOnline(model_id, ge_root_model, listener); } GE_CHK_STATUS_RET(SetDevice(static_cast(GetContext().DeviceId())), "Set device failed, model id:%u.", model_id); mmTimespec timespec = mmGetTickCount(); std::shared_ptr davinci_model = MakeShared(0, listener); if (davinci_model == nullptr) { GELOGE(FAILED, "davinci_model is nullptr"); return FAILED; } davinci_model->SetId(model_id); davinci_model->SetDeviceId(GetContext().DeviceId()); auto root_graph = ge_root_model->GetRootGraph(); GE_CHECK_NOTNULL(root_graph); string root_model_name = root_graph->GetName(); auto name_to_model = ge_root_model->GetSubgraphInstanceNameToModel(); GeModelPtr ge_model = name_to_model[root_model_name]; Status ret = SUCCESS; do { GE_TIMESTAMP_START(Assign); GE_IF_BOOL_EXEC(SUCCESS != (ret = davinci_model->Assign(ge_model)), GELOGW("assign model to modeldef failed."); break;); GE_TIMESTAMP_END(Assign, "GraphLoader::ModelAssign"); GE_TIMESTAMP_START(Init); GE_IF_BOOL_EXEC(SUCCESS != (ret = davinci_model->Init()), GELOGW("DavinciInit failed."); break;); GE_TIMESTAMP_END(Init, "GraphLoader::ModelInit"); InsertModel(model_id, davinci_model); GELOGI("Parse model %u success.", model_id); if (ProfilingManager::Instance().ProfilingOn()) { davinci_model->SetProfileTime(MODEL_LOAD_START, (timespec.tv_sec * 1000 * 1000 * 1000 + timespec.tv_nsec)); // 1000 ^ 3 converts second to nanosecond davinci_model->SetProfileTime(MODEL_LOAD_END); if (davinci_model->SinkModelProfile() != SUCCESS) { GELOGW("Sink model profile failed."); } } } while (0); GE_CHK_RT(rtDeviceReset(static_cast(GetContext().DeviceId()))); return ret; } void ModelManager::InsertModel(uint32_t id, std::shared_ptr &davinci_model) { GE_CHK_BOOL_EXEC(davinci_model != nullptr, return, "davinci_model ptr is null, id: %u", id); std::lock_guard lock(map_mutex_); model_map_[id] = davinci_model; } void ModelManager::InsertModel(uint32_t id, shared_ptr &hybrid_model) { GE_CHK_BOOL_EXEC(hybrid_model != nullptr, return, "hybrid_model ptr is null, id: %u", id); std::lock_guard lock(map_mutex_); hybrid_model_map_[id] = hybrid_model; } Status ModelManager::DeleteModel(uint32_t id) { std::lock_guard lock(map_mutex_); auto it = model_map_.find(id); auto hybrid_model_it = hybrid_model_map_.find(id); if (it != model_map_.end()) { uint64_t session_id = it->second->GetSessionId(); std::string model_key = std::to_string(session_id) + "_" + std::to_string(id); auto iter_aicpu_kernel = model_aicpu_kernel_.find(model_key); if (iter_aicpu_kernel != model_aicpu_kernel_.end()) { (void)model_aicpu_kernel_.erase(iter_aicpu_kernel); } (void)model_map_.erase(it); } else if (hybrid_model_it != hybrid_model_map_.end()) { (void)hybrid_model_map_.erase(hybrid_model_it); } else { GELOGE(PARAM_INVALID, "model id %u does not exists.", id); return PARAM_INVALID; } return SUCCESS; } std::shared_ptr ModelManager::GetModel(uint32_t id) { std::lock_guard lock(map_mutex_); auto it = model_map_.find(id); return (it == model_map_.end()) ? nullptr : it->second; } std::shared_ptr ModelManager::GetHybridModel(uint32_t id) { std::lock_guard lock(map_mutex_); auto it = hybrid_model_map_.find(id); return (it == hybrid_model_map_.end()) ? nullptr : it->second; } Status ModelManager::Unload(uint32_t model_id) { GE_CHK_STATUS_RET(DeleteModel(model_id), "failed to unload model id: %u", model_id); if (device_count > 0) { device_count--; GELOGI("Unload model %u success.", model_id); } else { GELOGI("Unload model %u success.no need reset device,device_count: %u", model_id, device_count); } return SUCCESS; } Status ModelManager::UnloadModeldef(uint32_t model_id) { GE_CHK_STATUS_RET(DeleteModel(model_id), "failed to unload modeldef id: %u", model_id); return SUCCESS; } Status ModelManager::DataInput(const InputData &input_data, OutputData &output_data) { GELOGI("calling the DataInput"); shared_ptr data_wrap(new (std::nothrow) InputDataWrapper()); GE_CHECK_NOTNULL(data_wrap); Status status = data_wrap->Init(input_data, output_data); if (status != SUCCESS) { GELOGE(domi::PUSH_DATA_FAILED, "Init InputDataWrapper failed, input data index: %u.", input_data.index); return domi::PUSH_DATA_FAILED; } uint32_t model_id = input_data.model_id; output_data.model_id = model_id; std::shared_ptr model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(model != nullptr, PARAM_INVALID, "Invalid Model ID %u in InputData! ", model_id); GE_IF_BOOL_EXEC(model->GetDataInputTid() == 0, model->SetDataInputTid(mmGetTid())); DataInputer *inputer = model->GetDataInputer(); GE_CHECK_NOTNULL(inputer); if (inputer->Push(data_wrap) != SUCCESS) { GELOGE(domi::DATA_QUEUE_ISFULL, "Data queue is full, please call again later, model_id %u ", model_id); return domi::DATA_QUEUE_ISFULL; } GELOGD("Data input success, model id:%u", model_id); return SUCCESS; } /// /// @ingroup domi_ome /// @brief load Input and output TensorInfo for Model /// @return Status run result /// Status ModelManager::DataInputTensor(uint32_t model_id, const std::vector &inputs) { std::shared_ptr model = GetModel(model_id); auto hybrid_model = GetHybridModel(model_id); if (hybrid_model == nullptr) { GE_CHECK_NOTNULL(model); } InputData input_data; input_data.model_id = model_id; input_data.timeout = 0; input_data.timestamp = 0; input_data.index = 0; for (size_t i = 0; i < inputs.size(); ++i) { DataBuffer data; data.data = inputs[i].data; data.length = static_cast(inputs[i].length); input_data.blobs.push_back(data); } OutputData output_data; output_data.model_id = model_id; output_data.index = 0; shared_ptr data_wrap(new (std::nothrow) InputDataWrapper()); GE_CHECK_NOTNULL(data_wrap); GE_CHK_STATUS_EXEC(data_wrap->Init(input_data, output_data), return domi::PUSH_DATA_FAILED, "Init InputDataWrapper failed,input data model_id is : %u.", model_id); if (hybrid_model != nullptr) { GE_CHK_STATUS_RET(hybrid_model->EnqueueData(data_wrap), "Data queue is full, please call again later, model_id %u ", model_id); return SUCCESS; } GE_CHK_BOOL_RET_STATUS(model != nullptr, PARAM_INVALID, "Invalid Model ID %u in InputData! ", model_id); DataInputer *inputer = model->GetDataInputer(); GE_CHECK_NOTNULL(inputer); GE_CHK_STATUS_EXEC(inputer->Push(data_wrap), return domi::DATA_QUEUE_ISFULL, "Data queue is full, please call again later, model_id %u ", model_id); GELOGD("Data input success, model id:%u", model_id); return SUCCESS; } /// /// @ingroup domi_ome /// @brief create model thread, start to execute model /// @param [in] model_id Model ID to be started /// @return Status model run result /// @author /// Status ModelManager::Start(uint32_t model_id) { auto hybrid_model = GetHybridModel(model_id); if (hybrid_model != nullptr) { GE_CHK_STATUS_RET_NOLOG(hybrid_model->ModelRunStart()); GELOGI("Start hybrid model %u success.", model_id); return SUCCESS; } std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to start! ", model_id); Status status = davinci_model->ModelRunStart(); if (status == SUCCESS) { GELOGI("Start model %u success.", model_id); } return status; } /// /// @ingroup domi_ome /// @brief Model ID stop /// @only when unloaded /// @param [in] model_id Model ID to be stopped /// @return Status model stop result /// @author /// Status ModelManager::Stop(uint32_t model_id) { auto hybrid_model = GetHybridModel(model_id); if (hybrid_model != nullptr) { GE_CHK_STATUS_RET_NOLOG(hybrid_model->ModelRunStop()); GELOGI("Stop hybrid model %u success.", model_id); return SUCCESS; } std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to stop!", model_id); Status status = davinci_model->ModelRunStop(); if (status == SUCCESS) { GELOGI("Stop model %u success.", model_id); } return status; } /// /// @ingroup domi_ome /// @brief Command handle /// @iterator 1 only Ieference, Debug 2 modes /// @param [in] command command to handle /// @return Status command handle result /// @author /// Status ModelManager::HandleCommand(const Command &command) { static const std::map> cmds = { {"profile", HandleProfileCommand}, {"dump", HandleDumpCommand}, {"profiling", HandleAclProfilingCommand}}; auto iter = cmds.find(command.cmd_type); if (iter == cmds.end()) { GELOGE(PARAM_INVALID, "Unsupported command: %s", command.cmd_type.c_str()); return PARAM_INVALID; } else { return iter->second(command); } } Status ModelManager::HandleAclProfilingCommand(const Command &command) { if (command.cmd_params.size() < kCmdParSize) { GELOGE(PARAM_INVALID, "When the cmd_type is 'profiling', the size of cmd_params must larger than 2."); return PARAM_INVALID; } std::string map_key = command.cmd_params[0]; std::string value = command.cmd_params[1]; if (map_key == PROFILE_CONFIG) { ProfilingManager::Instance().SetProfilingConfig(value); } return SUCCESS; } Status ModelManager::HandleProfileCommand(const Command &command) { if (command.cmd_params.size() < kCmdParSize) { GELOGE(PARAM_INVALID, "When the cmd_type is 'profile', the size of cmd_params must larger than 2."); return PARAM_INVALID; } std::string map_key = command.cmd_params[0]; std::string value = command.cmd_params[1]; GELOGI("Profiling mode, Command key:%s , value:%s ", map_key.c_str(), value.c_str()); auto iter = PROFILE_COMPONENT_MAP.find(map_key); if (iter != PROFILE_COMPONENT_MAP.end()) { std::string property_value = (value == "on") ? "1" : "0"; PropertiesManager::Instance().SetPropertyValue(iter->second, property_value); } if ((map_key == PROFILER_JOBCTX || map_key == PROFILER_TARGET_PATH || map_key == RTS_PROFILE_PATH)) { PropertiesManager::Instance().SetPropertyValue(map_key, value); } if ((map_key == PROFILE_STOP_KEY) && (value == PROFILE_STOP_VALUE)) { rtError_t rt_ret = rtProfilerStop(); if (rt_ret != RT_ERROR_NONE) { GELOGE(PARAM_INVALID, "Call rtProfilerStop ret:%d", rt_ret); return PARAM_INVALID; } } return SUCCESS; } static Status ParserPara(const Command &command, const string &dump_key, string &dump_value) { auto iter = std::find(command.cmd_params.begin(), command.cmd_params.end(), dump_key); if (iter != command.cmd_params.end()) { ++iter; if (iter == command.cmd_params.end()) { GELOGE(PARAM_INVALID, "Invalid access."); return PARAM_INVALID; } dump_value = *iter; } return SUCCESS; } Status ModelManager::HandleDumpCommand(const Command &command) { if (command.cmd_params.size() % kDumpCmdPairSize != 0) { GELOGE(PARAM_INVALID, "When the cmd_type is 'dump', the size of cmd_params must be a even number."); return PARAM_INVALID; } std::string dump_status("off"); std::string dump_model(DUMP_ALL_MODEL); std::string dump_path("/"); std::string dump_mode("output"); std::set dump_layers; auto ret = ParserPara(command, DUMP_STATUS, dump_status); if (ret != SUCCESS) { GELOGE(PARAM_INVALID, "parser dump status failed"); return FAILED; } GELOGI("dump status = %s.", dump_status.c_str()); ret = ParserPara(command, DUMP_MODEL, dump_model); if (ret != SUCCESS) { GELOGE(PARAM_INVALID, "parser dump model failed"); return FAILED; } GELOGI("dump status = %s.", dump_model.c_str()); if (dump_status == "off" || dump_status == "OFF") { PropertiesManager::Instance().DeleteDumpPropertyValue(dump_model); return SUCCESS; } for (size_t i = 0; i < command.cmd_params.size() / kDumpCmdPairSize; ++i) { if (command.cmd_params.at(i * kDumpCmdPairSize).find(DUMP_LAYER) != std::string::npos) { GELOGI("dump layer: %s.", command.cmd_params.at(i * kDumpCmdPairSize + 1).c_str()); dump_layers.insert(command.cmd_params.at(i * kDumpCmdPairSize + 1)); } } ret = ParserPara(command, DUMP_FILE_PATH, dump_path); if (ret != SUCCESS) { GELOGE(PARAM_INVALID, "parser dump path failed"); return FAILED; } if (!dump_path.empty() && dump_path[dump_path.size() - 1] != '/') { dump_path = dump_path + "/" + CurrentTimeInStr() + "/"; } GELOGI("dump status = %s.", dump_path.c_str()); ret = ParserPara(command, DUMP_MODE, dump_mode); if (ret != SUCCESS) { GELOGE(PARAM_INVALID, "parser dump mode failed"); return FAILED; } GELOGI("dump mode = %s", dump_mode.c_str()); auto iter_dump_mode = std::find(command.cmd_params.begin(), command.cmd_params.end(), DUMP_MODE); if (iter_dump_mode != command.cmd_params.end()) { ++iter_dump_mode; if (iter_dump_mode == command.cmd_params.end()) { GELOGE(PARAM_INVALID, "Invalid access."); return PARAM_INVALID; } dump_mode = *iter_dump_mode; GELOGI("dump mode = %s", dump_mode.c_str()); } PropertiesManager::Instance().AddDumpPropertyValue(dump_model, dump_layers); PropertiesManager::Instance().SetDumpOutputPath(dump_path); PropertiesManager::Instance().SetDumpMode(dump_mode); return SUCCESS; } Status ModelManager::GetMaxUsedMemory(const uint32_t model_id, uint64_t &max_size) { auto hybrid_model = GetHybridModel(model_id); if (hybrid_model != nullptr) { max_size = 0; return SUCCESS; } std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetMaxUsedMemory Failed, Invalid Model ID %u !", model_id); max_size = davinci_model->TotalMemSize(); return SUCCESS; } Status ModelManager::GetInputOutputDescInfo(const uint32_t model_id, vector &input_desc, vector &output_desc) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); return davinci_model->GetInputOutputDescInfo(input_desc, output_desc); } Status ModelManager::GetInputOutputDescInfo(const uint32_t model_id, vector &input_desc, vector &output_desc, std::vector &inputFormats, std::vector &outputFormats, bool new_model_desc) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); davinci_model->SetModelDescVersion(new_model_desc); return davinci_model->GetInputOutputDescInfo(input_desc, output_desc, inputFormats, outputFormats); } /// /// @ingroup ge /// @brief Get dynamic batch_info /// @param [in] model_id /// @param [out] batch_info /// @return execute result /// Status ModelManager::GetDynamicBatchInfo(const uint32_t model_id, std::vector> &batch_info) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetDynamicBatchInfo Failed, Invalid Model ID %u !", model_id); return davinci_model->GetDynamicBatchInfo(batch_info); } Status ModelManager::GetCurShape(const uint32_t model_id, std::vector &batch_info) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHECK_NOTNULL(davinci_model); davinci_model->GetCurShape(batch_info); return SUCCESS; } Status ModelManager::GetModelAttr(uint32_t model_id, std::vector &dynamic_output_shape_info) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHECK_NOTNULL(davinci_model); davinci_model->GetModelAttr(dynamic_output_shape_info); return SUCCESS; } Status ModelManager::GetInputOutputDescInfoForZeroCopy(const uint32_t model_id, vector &input_desc, vector &output_desc, std::vector &inputFormats, std::vector &outputFormats) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); return davinci_model->GetInputOutputDescInfoForZeroCopy(input_desc, output_desc, inputFormats, outputFormats); } /// /// @ingroup ge /// @brief Get AIPP info /// @param [in] model_id /// @param [in] index /// @param [out] aipp_info /// @return execute result /// Status ModelManager::GetAIPPInfo(const uint32_t model_id, uint32_t index, AippConfigInfo &aipp_info) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetAIPPInfo failed, invalid model_id is %u.", model_id); return davinci_model->GetAIPPInfo(index, aipp_info); } Status ModelManager::GenSessionId(uint64_t &session_id) { std::lock_guard lock(session_id_create_mutex_); struct timeval tv; if (gettimeofday(&tv, nullptr) != 0) { GELOGE(INTERNAL_ERROR, "Failed to get current time."); return INTERNAL_ERROR; } session_id = static_cast(tv.tv_sec * 1000000 + tv.tv_usec); // 1000000us session_id_bias_++; // max bais 100. session_id_bias_ = session_id_bias_ % 100; session_id = session_id * 100 + session_id_bias_; GELOGD("Generate new session id: %lu.", session_id); return SUCCESS; } Status ModelManager::UpdateSessionId(std::shared_ptr &davinci_model, uint64_t session_id) { GeModelPtr ge_model_current = davinci_model->GetGeModel(); GE_CHECK_NOTNULL(ge_model_current); if (!ge::AttrUtils::SetInt(ge_model_current, ge::MODEL_ATTR_SESSION_ID, static_cast(session_id))) { GELOGW("Set attr[%s] failed in updating session_id.", MODEL_ATTR_SESSION_ID.c_str()); } GELOGD("Update session id: %lu.", session_id); return SUCCESS; } Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model, shared_ptr listener, void *dev_ptr, size_t mem_size, void *weight_ptr, size_t weight_size) { GE_CHK_BOOL_RET_STATUS(model.key.empty() || access(model.key.c_str(), F_OK) == 0, PARAM_INVALID, "input key file path is not valid, %s", strerror(errno)); GenModelId(&model_id); shared_ptr davinci_model = nullptr; mmTimespec timespec = mmGetTickCount(); ModelHelper model_helper; Status ret = model_helper.LoadModel(model); if (ret != SUCCESS) { GELOGE(ret, "load model failed."); return ret; } do { GeModelPtr ge_model = model_helper.GetGeModel(); try { davinci_model = std::make_shared(model.priority, listener); } catch (std::bad_alloc &) { GELOGE(FAILED, "Make shared failed"); return FAILED; } catch (...) { GELOGE(FAILED, "Make shared failed since other exception raise"); return FAILED; } ret = davinci_model->Assign(ge_model); if (ret != SUCCESS) { GELOGW("assign model failed."); break; } davinci_model->SetId(model_id); int32_t device_id = 0; rtError_t rt_ret = rtGetDevice(&device_id); if (rt_ret != RT_ERROR_NONE || device_id < 0) { GELOGE(RT_FAILED, "Call rtGetDevice failed, ret = 0x%X, device_id = %d.", rt_ret, device_id); return FAILED; } davinci_model->SetDeviceId(device_id); davinci_model->SetOmName(model.om_name); /// In multi-threaded inference, using the same session_id among multiple threads may cause some threads to fail. /// These session_ids come from the same model, so the values of session_id are the same. /// Update session_id for infer in load model to avoid the same session_id. uint64_t new_session_id; ret = GenSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, break, "Generate session_id for infer failed."); ret = UpdateSessionId(davinci_model, new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, break, "Update session_id for infer failed."); ret = davinci_model->Init(dev_ptr, mem_size, weight_ptr, weight_size); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, break, "DavinciInit failed."); InsertModel(model_id, davinci_model); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(davinci_model == nullptr, ret = PARAM_INVALID; break, "Insert model failed"); GELOGI("Parse model %u success.", model_id); if (ProfilingManager::Instance().ProfilingOn()) { davinci_model->SetProfileTime(MODEL_LOAD_START, (timespec.tv_sec * 1000 * 1000 * 1000 + timespec.tv_nsec)); // 1000 ^ 3 converts second to nanosecond davinci_model->SetProfileTime(MODEL_LOAD_END); if (davinci_model->SinkModelProfile() != SUCCESS) { GELOGW("Sink model profile failed."); } } GE_IF_BOOL_EXEC(ret == SUCCESS, device_count++); return SUCCESS; } while (0); return ret; } /// /// @ingroup ge /// @brief ACL case, Load task list with queue. /// @param [out] model_id: model id for manager. /// @param [in] model_data: Model data load from offline model file. /// @param [in] input_que_ids: input queue ids from user, num equals Data Op. /// @param [in] output_que_ids: input queue ids from user, num equals NetOutput Op. /// @return: 0 for success / others for fail /// Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_data, const std::vector &input_queue_ids, const std::vector &output_queue_ids) { GE_CHK_BOOL_RET_STATUS(model_data.key.empty() || access(model_data.key.c_str(), F_OK) == 0, PARAM_INVALID, "input key file path is not valid, %s", strerror(errno)); ModelHelper model_helper; Status ret = model_helper.LoadModel(model_data); if (ret != SUCCESS) { GELOGE(ret, "load model failed."); return ret; } shared_ptr davinci_model = MakeShared(model_data.priority, nullptr); if (davinci_model == nullptr) { GELOGE(FAILED, "create model failed."); return FAILED; } ret = davinci_model->Assign(model_helper.GetGeModel()); if (ret != SUCCESS) { GELOGE(ret, "assign model failed."); return ret; } /// In multi-threaded inference, using the same session_id among multiple threads may cause some threads to fail. /// These session_ids come from the same model, so the values of session_id are the same. /// Update session_id for infer in load model to avoid the same session_id. uint64_t new_session_id; ret = GenSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Generate session_id for infer failed."); ret = UpdateSessionId(davinci_model, new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Update session_id for infer failed."); GenModelId(&model_id); davinci_model->SetId(model_id); ret = davinci_model->SetQueIds(input_queue_ids, output_queue_ids); if (ret != SUCCESS) { GELOGE(ret, "set model queue ids failed."); return ret; } ret = davinci_model->Init(); if (ret != SUCCESS) { GELOGE(ret, "init model failed."); return ret; } InsertModel(model_id, davinci_model); GELOGI("Parse model %u success.", model_id); return SUCCESS; } /// /// @ingroup domi_ome /// @brief ACL case, not start new thread, return result /// @param [in] model_id mode id /// @param [in] stream model stream /// @param [in] async_mode is asynchronize mode. /// @param [in] input_data input data /// @param [out] output_data output data /// Status ModelManager::ExecuteModel(uint32_t model_id, rtStream_t stream, bool async_mode, const InputData &input_data, OutputData &output_data) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to start! ", model_id); GeModelPtr ge_model_current = davinci_model->GetGeModel(); bool need_destroy_aicpu_kernel = false; bool result = ge::AttrUtils::GetBool(ge_model_current, kNeedDestroySpecifiedAicpuKernel, need_destroy_aicpu_kernel); if (result && need_destroy_aicpu_kernel) { GELOGI("Get attr %s successfully, start to destroy specified aicpu kernel.", kNeedDestroySpecifiedAicpuKernel); // Zero copy is enabled by default, no need to judge. uint64_t session_id_davinci = davinci_model->GetSessionId(); uint32_t model_id_davinci = davinci_model->GetModelId(); Status status = DestroyAicpuKernel(session_id_davinci, model_id_davinci); if (status != SUCCESS) { GELOGW("Destroy specified aicpu kernel failed, session id is %lu, model id is %u.", session_id_davinci, model_id_davinci); } } Status status = davinci_model->NnExecute(stream, async_mode, input_data, output_data); if (status == SUCCESS) { GELOGI("Execute model %u success.", model_id); } return status; } Status ModelManager::CreateAicpuSession(uint64_t session_id) { std::lock_guard lock(sess_ids_mutex_); auto it = sess_ids_.find(session_id); // never been created by any model if (it == sess_ids_.end()) { Status ret = KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType::FWK_ADPT_SESSION_CREATE, session_id, 0); if (ret == SUCCESS) { (void)sess_ids_.insert(session_id); GELOGI("The session: %lu create success.", session_id); } return ret; } return SUCCESS; } /// /// @ingroup ge /// @brief get model memory size and weight /// @param [in] const ModelData model: model type /// @param [out] size_t memSize: model memory usage /// size_t weightSize: model weight and memory size /// @return SUCCESS success / others failure /// Status ModelManager::GetModelMemAndWeightSize(const ModelData &model, size_t &mem_size, size_t &weight_size) { uint8_t *model_data = nullptr; uint32_t model_len = 0; Status ret = DavinciModelParser::ParseModelContent(model, model_data, model_len); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "parse model content failed!"); OmFileLoadHelper om_file_helper; ret = om_file_helper.Init(model_data, model_len); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "om file helperInit failed!"); auto partition_table = reinterpret_cast(model_data); if (partition_table->num == 1) { GELOGE(FAILED, "om model is error,please use executable om model"); return FAILED; } ModelPartition task_partition; if (om_file_helper.GetModelPartition(ModelPartitionType::TASK_INFO, task_partition) != SUCCESS) { GELOGE(FAILED, "get task model partition failed."); return FAILED; } std::shared_ptr model_task_def = MakeShared(); if (model_task_def == nullptr) { return FAILED; } if (task_partition.size != 0) { if (!ReadProtoFromArray(task_partition.data, static_cast(task_partition.size), model_task_def.get())) { GELOGE(FAILED, "ReadProtoFromArray failed."); return FAILED; } } ModelPartition partition_weight; ret = om_file_helper.GetModelPartition(ModelPartitionType::WEIGHTS_DATA, partition_weight); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Get weight partition failed. ret = %u", ret); mem_size = model_task_def->memory_size(); weight_size = partition_weight.size; return SUCCESS; } void ModelManager::GenModelId(uint32_t *id) { if (id == nullptr) { return; } std::lock_guard lock(map_mutex_); *id = ++max_model_id_; } Status ModelManager::GetOrigInputInfo(uint32_t model_id, uint32_t index, OriginInputInfo &orig_input_info) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetOrigInputInfo failed, invalid model_id is %u.", model_id); return davinci_model->GetOrigInputInfo(index, orig_input_info); } Status ModelManager::GetAllAippInputOutputDims(uint32_t model_id, uint32_t index, std::vector &input_dims, std::vector &output_dims) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetAllAippInputOutputDims failed, invalid model_id is %u.", model_id); return davinci_model->GetAllAippInputOutputDims(index, input_dims, output_dims); } } // namespace ge