| @@ -25,11 +25,6 @@ namespace hybrid { | |||
| std::map<uint32_t, std::unique_ptr<NpuMemoryAllocator>> NpuMemoryAllocator::allocators_; | |||
| std::mutex NpuMemoryAllocator::mu_; | |||
| AllocationAttr::AllocationAttr(int padding, void *try_reuse_addr) | |||
| : padding_(padding), try_reuse_addr_(try_reuse_addr) {} | |||
| AllocationAttr::AllocationAttr(int padding) : AllocationAttr(padding, nullptr) {} | |||
| AllocationAttr::AllocationAttr(void *try_reuse_addr) : AllocationAttr(0, try_reuse_addr) {} | |||
| NpuMemoryAllocator *NpuMemoryAllocator::GetAllocator() { | |||
| int32_t device_id = 0; | |||
| if (rtGetDevice(&device_id) != RT_ERROR_NONE) { | |||
| @@ -43,26 +38,15 @@ NpuMemoryAllocator *NpuMemoryAllocator::GetAllocator() { | |||
| NpuMemoryAllocator::NpuMemoryAllocator(uint32_t device_id) : device_id_(device_id) {} | |||
| void *NpuMemoryAllocator::Allocate(std::size_t size, AllocationAttr *attr) { | |||
| void *try_reuse_addr = nullptr; | |||
| size_t allocate_size = size; | |||
| if (attr != nullptr) { | |||
| try_reuse_addr = attr->try_reuse_addr_; | |||
| if (attr->padding_ != 0) { | |||
| // padding up to multiple of attr->padding, and add extra attr->padding_ | |||
| allocate_size = (size + 2 * attr->padding_ - 1) / attr->padding_ * attr->padding_; | |||
| GELOGD("Padding size %ld by %d. final size = %zu.", size, attr->padding_, allocate_size); | |||
| } | |||
| } | |||
| void *buffer = MemManager::CachingInstance(RT_MEMORY_HBM) | |||
| .Malloc(allocate_size, reinterpret_cast<uint8_t *>(try_reuse_addr), device_id_); | |||
| void *NpuMemoryAllocator::Allocate(std::size_t size, void *try_reuse_addr) { | |||
| void *buffer = | |||
| MemManager::CachingInstance(RT_MEMORY_HBM).Malloc(size, reinterpret_cast<uint8_t *>(try_reuse_addr), device_id_); | |||
| if (buffer == nullptr) { | |||
| GELOGE(MEMALLOC_FAILED, "Failed to malloc memory, device_id = %u, size = %zu", device_id_, allocate_size); | |||
| GELOGE(MEMALLOC_FAILED, "Failed to malloc memory, device_id = %u, size = %zu", device_id_, size); | |||
| return nullptr; | |||
| } | |||
| GELOGI("Allocating buffer of size %zu successfully. device_id = %u, address = %p", allocate_size, device_id_, buffer); | |||
| GELOGI("Allocating buffer of size %u successfully. device_id = %u, address = %p", size, device_id_, buffer); | |||
| return buffer; | |||
| } | |||
| @@ -26,35 +26,16 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class AllocationAttr { | |||
| public: | |||
| explicit AllocationAttr(int padding); | |||
| explicit AllocationAttr(void *try_reuse_addr); | |||
| AllocationAttr(int padding, void *try_reuse_addr); | |||
| ~AllocationAttr() = default; | |||
| private: | |||
| friend class NpuMemoryAllocator; | |||
| int padding_ = 0; | |||
| void *try_reuse_addr_ = nullptr; | |||
| }; | |||
| class NpuMemoryAllocator { | |||
| public: | |||
| ~NpuMemoryAllocator() = default; | |||
| static NpuMemoryAllocator *GetAllocator(uint32_t device_id); | |||
| static NpuMemoryAllocator *GetAllocator(); | |||
| static void DestroyAllocator(); | |||
| static AllocationAttr *AttrWithDefaultPadding() { | |||
| static AllocationAttr attr(kDefaultPadding, nullptr); | |||
| return &attr; | |||
| } | |||
| void *Allocate(std::size_t size, AllocationAttr *attr = nullptr); | |||
| void *Allocate(std::size_t size, void *try_reuse_addr = nullptr); | |||
| void Deallocate(void *data); | |||
| static constexpr int kDefaultPadding = 32; | |||
| private: | |||
| explicit NpuMemoryAllocator(uint32_t device_id); | |||
| uint32_t device_id_; | |||
| @@ -24,7 +24,7 @@ namespace hybrid { | |||
| TensorBuffer::TensorBuffer(NpuMemoryAllocator *allocator, void *buffer, size_t size) | |||
| : allocator_(allocator), buffer_(buffer), size_(size) {} | |||
| std::unique_ptr<TensorBuffer> TensorBuffer::Create(NpuMemoryAllocator *allocator, size_t size, AllocationAttr *attr) { | |||
| std::unique_ptr<TensorBuffer> TensorBuffer::Create(NpuMemoryAllocator *allocator, size_t size) { | |||
| void *buffer = nullptr; | |||
| if (size == 0) { | |||
| GELOGD("size is 0"); | |||
| @@ -36,7 +36,7 @@ std::unique_ptr<TensorBuffer> TensorBuffer::Create(NpuMemoryAllocator *allocator | |||
| return nullptr; | |||
| } | |||
| buffer = allocator->Allocate(size, attr); | |||
| buffer = allocator->Allocate(size); | |||
| if (buffer == nullptr) { | |||
| GELOGE(MEMALLOC_FAILED, "Failed to allocate memory. size = %zu", size); | |||
| return nullptr; | |||
| @@ -24,12 +24,10 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class NpuMemoryAllocator; | |||
| class AllocationAttr; | |||
| class TensorBuffer { | |||
| public: | |||
| static std::unique_ptr<TensorBuffer> Create(NpuMemoryAllocator *allocator, size_t size, | |||
| AllocationAttr *attr = nullptr); | |||
| static std::unique_ptr<TensorBuffer> Create(NpuMemoryAllocator *allocator, size_t size); | |||
| static std::unique_ptr<TensorBuffer> Create(void *buffer, size_t size); | |||
| @@ -17,5 +17,34 @@ | |||
| #include "hybrid_execution_context.h" | |||
| namespace ge { | |||
| namespace hybrid {} // namespace hybrid | |||
| namespace hybrid { | |||
| NodeStatePtr GraphExecutionContext::GetOrCreateNodeState(const NodePtr &node) { | |||
| auto &node_state = node_states[node]; | |||
| if (node_state == nullptr) { | |||
| const NodeItem *node_item = model->GetNodeItem(node); | |||
| if (node_item == nullptr) { | |||
| return nullptr; | |||
| } | |||
| node_state.reset(new (std::nothrow) NodeState(*node_item)); | |||
| } | |||
| return node_state; | |||
| } | |||
| void GraphExecutionContext::OnError(Status error_code) { | |||
| GELOGE(error_code, "Error occurred while executing model"); | |||
| { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| this->status = error_code; | |||
| } | |||
| compile_queue.Stop(); | |||
| execution_queue.Stop(); | |||
| } | |||
| Status GraphExecutionContext::GetStatus() { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| return status; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -20,7 +20,6 @@ | |||
| #include <atomic> | |||
| #include <unordered_map> | |||
| #include "common/blocking_queue.h" | |||
| #include "framework/common/debug/ge_log.h" | |||
| #include "hybrid/common/npu_memory_allocator.h" | |||
| #include "hybrid/common/tensor_value.h" | |||
| #include "hybrid/executor/hybrid_profiler.h" | |||
| @@ -34,26 +33,34 @@ namespace hybrid { | |||
| struct GraphExecutionContext { | |||
| uint64_t session_id = 0; | |||
| const HybridModel *model = nullptr; | |||
| NodeDoneManager cv_manager; | |||
| BlockingQueue<NodeStatePtr> compile_queue; | |||
| BlockingQueue<NodeStatePtr> execution_queue; | |||
| std::vector<TensorValue> all_inputs; | |||
| std::vector<TensorValue> all_outputs; | |||
| std::unordered_map<NodePtr, NodeStatePtr> node_states; | |||
| rtStream_t stream = nullptr; | |||
| rtContext_t rt_context = nullptr; | |||
| rtContext_t rt_gen_context = nullptr; | |||
| std::unique_ptr<CallbackManager> callback_manager; | |||
| NpuMemoryAllocator *allocator = nullptr; | |||
| mutable std::unique_ptr<HybridProfiler> profiler; | |||
| bool trace_enabled = false; | |||
| long profiling_level = 0; | |||
| int profiling_level = 0; | |||
| bool dump_enabled = false; | |||
| long iteration = 0; | |||
| Status status = SUCCESS; | |||
| std::mutex mu_; | |||
| NodeStatePtr GetOrCreateNodeState(const NodePtr &node); | |||
| void OnError(Status status); | |||
| Status GetStatus(); | |||
| }; | |||
| #define RECORD_PROFILING_EVENT(context, evt_type, fmt, category, node_name, ...) \ | |||
| #define RECORD_PROFILING_EVENT(context, event_type, fmt, category, node_name, ...) \ | |||
| do { \ | |||
| if ((context)->profiler != nullptr) { \ | |||
| if (node_name != nullptr) { \ | |||
| context->profiler->RecordEvent(evt_type, "tid:%lu [%s] [%s] " fmt, GetTid(), node_name, category, \ | |||
| ##__VA_ARGS__); \ | |||
| context->profiler->RecordEvent(event_type, "[%s] [%s] " fmt, node_name, category, ##__VA_ARGS__); \ | |||
| } else { \ | |||
| context->profiler->RecordEvent(evt_type, "tid:%lu [%s] " fmt, GetTid(), category, ##__VA_ARGS__); \ | |||
| context->profiler->RecordEvent(event_type, "[%s] " fmt, category, ##__VA_ARGS__); \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| @@ -72,6 +79,7 @@ struct GraphExecutionContext { | |||
| #define RECORD_CALLBACK_EVENT(context, name, fmt, ...) \ | |||
| RECORD_PROFILING_EVENT((context), HybridProfiler::CALLBACK, fmt, "Callback", name, ##__VA_ARGS__) | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_EXECUTOR_HYBRID_EXECUTION_CONTEXT_H_ | |||
| @@ -77,18 +77,19 @@ Status HybridModelAsyncExecutor::Init() { | |||
| GE_CHECK_NOTNULL(data_inputer_); | |||
| GE_CHK_RT_RET(rtStreamCreate(&stream_, RT_STREAM_PRIORITY_DEFAULT)); | |||
| executor_ = std::unique_ptr<HybridModelExecutor>(new (std::nothrow) HybridModelExecutor(model_, device_id_, stream_)); | |||
| GE_CHECK_NOTNULL(executor_); | |||
| GE_CHK_STATUS_RET(executor_->Init(), "Failed to init hybrid engine"); | |||
| engine_ = std::unique_ptr<HybridModelExecutor>(new (std::nothrow) HybridModelExecutor(model_, device_id_, stream_)); | |||
| GE_CHECK_NOTNULL(engine_); | |||
| GE_CHK_STATUS_RET(engine_->Init(), "Failed to init hybrid engine"); | |||
| GE_CHK_STATUS_RET(InitInputTensors(), "Failed to init input tensors"); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelAsyncExecutor::PreRun(InputData ¤t_data) { | |||
| GE_CHK_STATUS_RET(SyncVarData(), "Failed to sync var data"); | |||
| RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[SyncVarData] End"); | |||
| RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[SyncVarData] End"); | |||
| GE_CHK_STATUS_RET(CopyInputData(current_data), "Failed to copy input data to model"); | |||
| RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[CopyInputData] End"); | |||
| RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[CopyInputData] End"); | |||
| return SUCCESS; | |||
| } | |||
| @@ -118,21 +119,21 @@ Status HybridModelAsyncExecutor::RunInternal() { | |||
| args.inputs[it.first] = it.second; | |||
| } | |||
| RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[RunInternal] [iteration = %d] Start", iterator_count_); | |||
| RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[RunInternal] [iteration = %d] Start", iterator_count_); | |||
| ret = PreRun(current_data); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( | |||
| ret != SUCCESS, (void)HandleResult(ret, current_data.index, args, data_wrapper->GetOutput()); | |||
| ret != SUCCESS, (void)HandleResult(ret, current_data.index, args.outputs, data_wrapper->GetOutput()); | |||
| CsaInteract::GetInstance().StoreInternalErrorCode(ret, ERROR_MODULE_FMK, JOBSUBSTATE_GRAPH_EXEC); | |||
| continue, "PreRun failed."); // [No need to check value] | |||
| ret = executor_->Execute(args); | |||
| ret = HandleResult(ret, current_data.index, args, data_wrapper->GetOutput()); | |||
| ret = engine_->Execute(args); | |||
| ret = HandleResult(ret, current_data.index, args.outputs, data_wrapper->GetOutput()); | |||
| if (ret != SUCCESS) { | |||
| CsaInteract::GetInstance().StoreInternalErrorCode(ret, ERROR_MODULE_RUNTIME, JOBSUBSTATE_GRAPH_EXEC); | |||
| continue; | |||
| } | |||
| RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[RunInternal] [iteration = %d] End", iterator_count_); | |||
| RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[RunInternal] [iteration = %d] End", iterator_count_); | |||
| iterator_count_++; | |||
| GELOGI("run iterator count is %lu", iterator_count_); | |||
| } | |||
| @@ -142,8 +143,8 @@ Status HybridModelAsyncExecutor::RunInternal() { | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, HybridModelExecutor::ExecuteArgs &args, | |||
| OutputData *output_data) { | |||
| Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, | |||
| const std::vector<TensorValue> &output_tensors, OutputData *output_data) { | |||
| GELOGD("Start to handle result. model id = %u, data index = %u, execution ret = %u", model_id_, data_id, exec_ret); | |||
| std::vector<ge::OutputTensorInfo> output_tensor_info_list; | |||
| if (exec_ret == END_OF_SEQUENCE) { | |||
| @@ -157,7 +158,7 @@ Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, | |||
| } | |||
| GE_CHECK_NOTNULL(output_data); | |||
| auto ret = CopyOutputs(args, output_data, output_tensor_info_list); | |||
| auto ret = CopyOutputs(output_tensors, output_data, output_tensor_info_list); | |||
| if (ret != SUCCESS) { | |||
| OnComputeDone(data_id, INTERNAL_ERROR, output_tensor_info_list); | |||
| return INTERNAL_ERROR; | |||
| @@ -214,8 +215,9 @@ Status HybridModelAsyncExecutor::CopyInputData(const InputData ¤t_data) { | |||
| Status HybridModelAsyncExecutor::InitInputTensors() { | |||
| auto allocator = NpuMemoryAllocator::GetAllocator(device_id_); | |||
| GE_CHECK_NOTNULL(allocator); | |||
| int input_index = 0; | |||
| for (const auto &input_node : model_->GetRootGraphItem()->GetInputNodes()) { | |||
| for (const auto &it : model_->input_nodes_) { | |||
| auto input_index = it.first; | |||
| auto input_node = it.second; | |||
| GELOGD("Init input[%u], node = %s", input_index, input_node->NodeName().c_str()); | |||
| auto output_desc = input_node->op_desc->GetOutputDescPtr(kDataOutputIndex); | |||
| GE_CHECK_NOTNULL(output_desc); | |||
| @@ -233,7 +235,6 @@ Status HybridModelAsyncExecutor::InitInputTensors() { | |||
| TensorValue tensor(shared_ptr<TensorBuffer>(buffer.release())); | |||
| tensor.SetName("Input_" + input_node->NodeName()); | |||
| input_tensors_.emplace(input_index, tensor); | |||
| input_index += 1; | |||
| } | |||
| return SUCCESS; | |||
| @@ -249,33 +250,35 @@ Status HybridModelAsyncExecutor::OnComputeDone(uint32_t data_index, uint32_t res | |||
| return result_code; | |||
| } | |||
| Status HybridModelAsyncExecutor::CopyOutputs(HybridModelExecutor::ExecuteArgs &args, OutputData *output_data, | |||
| Status HybridModelAsyncExecutor::CopyOutputs(const std::vector<TensorValue> &output_tensors, OutputData *output_data, | |||
| std::vector<ge::OutputTensorInfo> &outputs) { | |||
| // copy output data from op to designated position | |||
| std::vector<ConstGeTensorDescPtr> &output_tensor_desc_list = args.output_desc; | |||
| std::vector<TensorValue> &output_tensors = args.outputs; | |||
| if (output_tensor_desc_list.size() != output_tensors.size()) { | |||
| NodeItem *net_output_node = model_->net_output_node_; | |||
| GE_CHECK_NOTNULL(net_output_node); | |||
| auto all_input_desc = net_output_node->op_desc->GetAllInputsDescPtr(); | |||
| if (all_input_desc.size() != output_tensors.size()) { | |||
| GELOGE(INTERNAL_ERROR, "Output sizes mismatch. From op_desc = %zu, and from output tensors = %zu", | |||
| output_tensor_desc_list.size(), output_tensors.size()); | |||
| all_input_desc.size(), output_tensors.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("Number of outputs = %zu", output_tensor_desc_list.size()); | |||
| GELOGD("Number of outputs = %zu", all_input_desc.size()); | |||
| for (size_t i = 0; i < output_tensors.size(); ++i) { | |||
| GELOGD("Start to process output[%zu]", i); | |||
| auto &output_tensor = output_tensors[i]; | |||
| auto &tensor_desc = output_tensor_desc_list.at(i); | |||
| auto &tensor_desc = all_input_desc.at(i); | |||
| GE_CHECK_NOTNULL(tensor_desc); | |||
| int64_t output_size = -1; | |||
| GE_CHK_GRAPH_STATUS_RET(TensorUtils::CalcTensorMemSize(tensor_desc->GetShape(), tensor_desc->GetFormat(), | |||
| GE_CHK_GRAPH_STATUS_RET(TensorUtils::CalcTensorMemSize(tensor_desc->MutableShape(), tensor_desc->GetFormat(), | |||
| tensor_desc->GetDataType(), output_size), | |||
| "Failed to calc tensor size for output[%zu]. shape = [%s], type = %s, format = %s", i, | |||
| tensor_desc->GetShape().ToString().c_str(), | |||
| tensor_desc->MutableShape().ToString().c_str(), | |||
| TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), | |||
| TypeUtils::FormatToSerialString(tensor_desc->GetFormat()).c_str()); | |||
| GELOGD("Got tensor size for output[%zu] successfully. shape = [%s], type = %s, format = %s, size = %ld", i, | |||
| tensor_desc->GetShape().ToString().c_str(), | |||
| tensor_desc->MutableShape().ToString().c_str(), | |||
| TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), | |||
| TypeUtils::FormatToSerialString(tensor_desc->GetFormat()).c_str(), output_size); | |||
| @@ -283,7 +286,7 @@ Status HybridModelAsyncExecutor::CopyOutputs(HybridModelExecutor::ExecuteArgs &a | |||
| GE_CHECK_LE(output_size, UINT32_MAX); | |||
| if (output_tensor.GetSize() < static_cast<size_t>(output_size)) { | |||
| GELOGE(INTERNAL_ERROR, "output[%zu] tensor size(%zu) is not enough for output shape [%s]", i, | |||
| output_tensor.GetSize(), tensor_desc->GetShape().ToString().c_str()); | |||
| output_tensor.GetSize(), tensor_desc->MutableShape().ToString().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| @@ -299,7 +302,7 @@ Status HybridModelAsyncExecutor::CopyOutputs(HybridModelExecutor::ExecuteArgs &a | |||
| output.data = std::move(data_buf); | |||
| output_data->blobs.emplace_back(data_buf.get(), static_cast<uint32_t>(output_size), false); | |||
| } else { | |||
| GELOGW("Output[%zu] is empty. shape = [%s]", i, tensor_desc->GetShape().ToString().c_str()); | |||
| GELOGW("Output[%zu] is empty. shape = [%s]", i, tensor_desc->MutableShape().ToString().c_str()); | |||
| output.data = nullptr; | |||
| output_data->blobs.emplace_back(nullptr, 0U, false); | |||
| } | |||
| @@ -307,53 +310,7 @@ Status HybridModelAsyncExecutor::CopyOutputs(HybridModelExecutor::ExecuteArgs &a | |||
| outputs.emplace_back(std::move(output)); | |||
| GELOGD("Output[%zu] added, type = %s, shape = [%s], size = %ld", i, | |||
| TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), | |||
| tensor_desc->GetShape().ToString().c_str(), output_size); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelAsyncExecutor::Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs) { | |||
| GELOGD("Start to execute model."); | |||
| // prepare inputs | |||
| InputData input_data; | |||
| for (auto &tensor : inputs) { | |||
| DataBuffer buffer; | |||
| buffer.data = const_cast<uint8_t *>(tensor.GetData().GetData()); | |||
| buffer.length = tensor.GetData().size(); | |||
| input_data.blobs.emplace_back(buffer); | |||
| } | |||
| GE_CHK_STATUS_RET(CopyInputData(input_data), "Failed to copy input data to model"); | |||
| GELOGD("Done copying input data successfully."); | |||
| HybridModelExecutor::ExecuteArgs args; | |||
| args.inputs.resize(input_tensors_.size()); | |||
| args.input_desc.resize(input_tensors_.size()); | |||
| for (auto &it : input_tensors_) { | |||
| args.inputs[it.first] = it.second; | |||
| args.input_desc[it.first] = MakeShared<GeTensorDesc>(inputs[it.first].GetTensorDesc()); | |||
| } | |||
| GE_CHK_STATUS_RET(executor_->Execute(args), "Failed to execute model."); | |||
| std::vector<ge::OutputTensorInfo> output_tensor_info_list; | |||
| OutputData output_data; | |||
| GE_CHK_STATUS_RET(CopyOutputs(args, &output_data, output_tensor_info_list), "Failed to copy outputs."); | |||
| GELOGD("Done copying output data successfully. output count = %zu", output_tensor_info_list.size()); | |||
| int out_index = 0; | |||
| outputs.resize(output_tensor_info_list.size()); | |||
| for (auto &out_tensor_info : output_tensor_info_list) { | |||
| auto &ge_tensor = outputs[out_index]; | |||
| if (out_tensor_info.length > 0) { | |||
| GE_CHK_GRAPH_STATUS_RET(ge_tensor.SetData(out_tensor_info.data.get(), out_tensor_info.length), | |||
| "Failed to set output[%d].", out_index); | |||
| } | |||
| ge_tensor.MutableTensorDesc() = *args.output_desc[out_index]; | |||
| GELOGD("Set output[%d], tensor size = %ld, shape = [%s]", out_index, out_tensor_info.length, | |||
| ge_tensor.MutableTensorDesc().MutableShape().ToString().c_str()); | |||
| ++out_index; | |||
| tensor_desc->MutableShape().ToString().c_str(), output_size); | |||
| } | |||
| return SUCCESS; | |||
| @@ -35,8 +35,6 @@ class HybridModelAsyncExecutor { | |||
| Status Init(); | |||
| Status Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs); | |||
| Status Start(const std::shared_ptr<ModelListener> &listener); | |||
| void SetDeviceId(uint32_t device_id); | |||
| @@ -54,10 +52,10 @@ class HybridModelAsyncExecutor { | |||
| Status SyncVarData(); | |||
| Status HandleResult(Status exec_ret, uint32_t data_id, HybridModelExecutor::ExecuteArgs &args, | |||
| Status HandleResult(Status exec_ret, uint32_t data_id, const std::vector<TensorValue> &output_tensors, | |||
| OutputData *output_data); | |||
| Status CopyOutputs(HybridModelExecutor::ExecuteArgs &args, OutputData *output_data, | |||
| Status CopyOutputs(const std::vector<TensorValue> &output_tensors, OutputData *output_data, | |||
| std::vector<ge::OutputTensorInfo> &outputs); | |||
| Status OnComputeDone(uint32_t data_index, uint32_t result_code, std::vector<ge::OutputTensorInfo> &outputs); | |||
| @@ -72,7 +70,7 @@ class HybridModelAsyncExecutor { | |||
| uint32_t model_id_ = 0U; | |||
| std::atomic_bool run_flag_; | |||
| std::unique_ptr<DataInputer> data_inputer_; | |||
| std::unique_ptr<HybridModelExecutor> executor_; | |||
| std::unique_ptr<HybridModelExecutor> engine_; | |||
| std::future<Status> future_; | |||
| uint64_t iterator_count_ = 0; | |||
| @@ -26,17 +26,17 @@ HybridModelExecutor::HybridModelExecutor(HybridModel *model, uint32_t device_id, | |||
| Status HybridModelExecutor::Init() { | |||
| GELOGD("Start to init HybridGraphEngine."); | |||
| GE_CHK_STATUS_RET_NOLOG(InitExecutionContext()); | |||
| infer_shape_engine_.reset(new (std::nothrow) ShapeInferenceEngine(&context_)); | |||
| compile_engine_.reset(new (std::nothrow) TaskCompileEngine(&context_)); | |||
| execute_engine_.reset(new (std::nothrow) ExecutionEngine(&context_, context_.callback_manager.get())); | |||
| GE_CHK_STATUS_RET_NOLOG(compile_engine_->Init()); | |||
| GELOGD("HybridGraphEngine initialized successfully."); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::Execute(HybridModelExecutor::ExecuteArgs &args) { | |||
| GELOGD("Start to execute model."); | |||
| auto root_graph_item = model_->GetRootGraphItem(); | |||
| GE_CHECK_NOTNULL(root_graph_item); | |||
| SubgraphExecutor executor(model_->GetRootGraphItem(), &context_); | |||
| auto ret = ExecuteGraphInternal(executor, args); | |||
| auto ret = ExecuteGraphInternal(args); | |||
| Cleanup(); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[Cleanup] End"); | |||
| GE_CHK_STATUS_RET(ret, "Failed to execute model"); | |||
| @@ -46,22 +46,24 @@ Status HybridModelExecutor::Execute(HybridModelExecutor::ExecuteArgs &args) { | |||
| context_.profiler->Reset(); | |||
| } | |||
| context_.iteration += 1; | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::ExecuteGraphInternal(SubgraphExecutor &executor, HybridModelExecutor::ExecuteArgs &args) { | |||
| Status HybridModelExecutor::ExecuteGraphInternal(HybridModelExecutor::ExecuteArgs &args) { | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitContext] Start"); | |||
| GE_CHK_STATUS_RET_NOLOG(ResetExecutionContext(context_)); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitContext] End"); | |||
| GE_CHK_STATUS_RET(executor.ExecuteAsync(args.inputs, args.input_desc), "Failed to execute partitioned call."); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[ExecuteAsync] End"); | |||
| GE_CHK_STATUS_RET(executor.Synchronize(), "Failed to sync root graph."); | |||
| GE_CHK_STATUS_RET_NOLOG(InitInputsAndOutputs(args, context_)); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitInputsAndOutputs] End"); | |||
| GE_CHK_STATUS_RET_NOLOG(compile_engine_->Start(pool_)); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[CompileProcess] Started"); | |||
| GE_CHK_STATUS_RET_NOLOG(infer_shape_engine_->Start(pool_)); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[InferShapeProcess] Started"); | |||
| GE_CHK_STATUS_RET(execute_engine_->Start(), "Run execution engine failed."); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[ExecutionProcess] End"); | |||
| GE_CHK_STATUS_RET_NOLOG(Synchronize()); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[Synchronize] End"); | |||
| GE_CHK_STATUS_RET(executor.GetOutputs(args.outputs, args.output_desc), "Failed to get outputs"); | |||
| GE_CHK_STATUS_RET_NOLOG(GetOutput(args)); | |||
| RECORD_MODEL_EXECUTION_EVENT(&context_, "[GetOutput] End"); | |||
| return SUCCESS; | |||
| } | |||
| @@ -69,16 +71,18 @@ Status HybridModelExecutor::ExecuteGraphInternal(SubgraphExecutor &executor, Hyb | |||
| Status HybridModelExecutor::Cleanup() { | |||
| GELOGD("Start to cleanup."); | |||
| context_.callback_manager->Destroy(); | |||
| context_.cv_manager.Reset(); | |||
| context_.node_states.clear(); | |||
| context_.all_inputs.clear(); | |||
| context_.all_outputs.clear(); | |||
| context_.compile_queue.Clear(); | |||
| context_.execution_queue.Clear(); | |||
| RuntimeInferenceContext::DestroyContext(to_string(context_.session_id)); | |||
| GELOGD("Cleanup successfully."); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::InitExecutionContext() { | |||
| GE_CHK_RT_RET(rtCtxGetCurrent(&context_.rt_context)); | |||
| GE_CHK_RT_RET(rtCtxCreate(&context_.rt_gen_context, RT_CTX_GEN_MODE, 0)); | |||
| GE_CHK_RT_RET(rtCtxSetCurrent(context_.rt_context)); | |||
| context_.stream = stream_; | |||
| context_.model = model_; | |||
| context_.session_id = ::ge::GetContext().SessionId(); | |||
| @@ -90,15 +94,78 @@ Status HybridModelExecutor::InitExecutionContext() { | |||
| if (IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) { | |||
| context_.trace_enabled = true; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::ResetExecutionContext(GraphExecutionContext &context) { | |||
| auto &model = *context.model; | |||
| context.all_inputs.resize(model.TotalInputs()); | |||
| context.all_outputs.resize(model.TotalOutputs()); | |||
| context.compile_queue.Restart(); | |||
| context.execution_queue.Restart(); | |||
| GE_CHK_STATUS_RET_NOLOG(context.callback_manager->Init()); | |||
| for (auto const_node : model.GetConstNodes()) { | |||
| auto weight_tensor = model.GetWeight(const_node); | |||
| GE_CHECK_NOTNULL(weight_tensor); | |||
| for (auto &dst_aid_and_nid : const_node->outputs[0]) { | |||
| auto *dst_node_item = dst_aid_and_nid.second; | |||
| auto input_offset = dst_node_item->input_start + dst_aid_and_nid.first; | |||
| context.all_inputs[input_offset] = *weight_tensor; | |||
| } | |||
| } | |||
| string ctx_id = std::to_string(context.session_id); | |||
| RuntimeInferenceContext::DestroyContext(ctx_id); | |||
| GE_CHK_GRAPH_STATUS_RET(RuntimeInferenceContext::CreateContext(ctx_id), "Failed to Destroy RuntimeInferenceContext"); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::InitInputsAndOutputs(HybridModelExecutor::ExecuteArgs &args, | |||
| GraphExecutionContext &context) { | |||
| for (const auto &it : model_->GetInputNodes()) { | |||
| uint32_t input_index = it.first; | |||
| if (input_index >= args.inputs.size()) { | |||
| GELOGE(PARAM_INVALID, "Not enough inputs. NumInputs = %zu, but input index = %u", args.inputs.size(), | |||
| input_index); | |||
| return PARAM_INVALID; | |||
| } | |||
| auto node_item = it.second; | |||
| auto &input_tensor = args.inputs[input_index]; | |||
| GELOGD("Set input tensor[%u] to inputs with index = %d, addr = %p, size = %zu", input_index, node_item->input_start, | |||
| input_tensor.GetData(), input_tensor.GetSize()); | |||
| context.all_inputs[node_item->input_start] = input_tensor; | |||
| } | |||
| for (size_t i = 0; i < model_->GetOutputOffsets().size(); ++i) { | |||
| auto offset = model_->GetOutputOffsets()[i]; | |||
| if (i < args.outputs.size() && args.outputs[i].GetData() != nullptr) { | |||
| GELOGD("Use user allocated output memory. output index = %zu, output offset = %d", i, offset); | |||
| context.all_outputs[offset] = args.outputs[i]; | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::Synchronize() { | |||
| GE_CHK_RT_RET(rtStreamSynchronize(stream_)); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelExecutor::GetOutput(HybridModelExecutor::ExecuteArgs &args) { | |||
| auto &net_output_input_offsets = model_->GetNetOutputInputOffsets(); | |||
| auto num_outputs = net_output_input_offsets.size(); | |||
| args.outputs.resize(num_outputs); | |||
| for (size_t i = 0; i < num_outputs; ++i) { | |||
| auto offset = net_output_input_offsets[i]; | |||
| GELOGI("Get output[%zu] from offset %d", i, offset); | |||
| args.outputs[i] = context_.all_inputs[offset]; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -20,7 +20,9 @@ | |||
| #include "graph/load/new_model_manager/data_inputer.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/rt_callback_manager.h" | |||
| #include "hybrid/executor/subgraph_executor.h" | |||
| #include "hybrid/executor/worker/execution_engine.h" | |||
| #include "hybrid/executor/worker/shape_inference_engine.h" | |||
| #include "hybrid/executor/worker/task_compile_engine.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| @@ -28,9 +30,7 @@ class HybridModelExecutor { | |||
| public: | |||
| struct ExecuteArgs { | |||
| std::vector<TensorValue> inputs; | |||
| std::vector<ConstGeTensorDescPtr> input_desc; | |||
| std::vector<TensorValue> outputs; | |||
| std::vector<ConstGeTensorDescPtr> output_desc; | |||
| }; | |||
| HybridModelExecutor(HybridModel *model, uint32_t device_id, rtStream_t stream); | |||
| @@ -44,15 +44,24 @@ class HybridModelExecutor { | |||
| Status Execute(ExecuteArgs &args); | |||
| private: | |||
| Status ExecuteGraphInternal(SubgraphExecutor &executor, ExecuteArgs &args); | |||
| Status ExecuteGraphInternal(ExecuteArgs &args); | |||
| Status Cleanup(); | |||
| Status InitExecutionContext(); | |||
| static Status ResetExecutionContext(GraphExecutionContext &context); | |||
| Status InitInputsAndOutputs(ExecuteArgs &args, GraphExecutionContext &context); | |||
| Status GetOutput(ExecuteArgs &args); | |||
| Status Synchronize(); | |||
| ThreadPool pool_; | |||
| HybridModel *model_; | |||
| uint32_t device_id_; | |||
| rtStream_t stream_; | |||
| GraphExecutionContext context_; | |||
| std::unique_ptr<ShapeInferenceEngine> infer_shape_engine_; | |||
| std::unique_ptr<TaskCompileEngine> compile_engine_; | |||
| std::unique_ptr<ExecutionEngine> execute_engine_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -59,10 +59,11 @@ void HybridProfiler::Dump(std::ostream &output_stream) { | |||
| auto first_evt = events_[0]; | |||
| auto start = first_evt.timestamp; | |||
| output_stream << "Start " << first_evt.desc << std::endl; | |||
| std::vector<decltype(start)> prev_timestamps; | |||
| prev_timestamps.resize(kMaxEventTypes, start); | |||
| for (int i = 0; i < counter_; ++i) { | |||
| for (int i = 1; i < counter_; ++i) { | |||
| auto &evt = events_[i]; | |||
| auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(evt.timestamp - start).count(); | |||
| auto &prev_ts = prev_timestamps[evt.event_type]; | |||
| @@ -15,49 +15,35 @@ | |||
| */ | |||
| #include "hybrid/executor/node_done_manager.h" | |||
| #include <chrono> | |||
| #include "framework/common/debug/ge_log.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr int kDefaultWaitTimeoutInSec = 10; | |||
| } | |||
| bool NodeDoneManager::Cond::Await() { | |||
| std::unique_lock<std::mutex> lk(cond_mu_); | |||
| if (!cv_.wait_for(lk, std::chrono::seconds(kDefaultWaitTimeoutInSec), | |||
| [&]() { return is_released_ || is_cancelled_; })) { | |||
| GELOGE(INTERNAL_ERROR, "Wait timed out."); | |||
| return false; | |||
| } | |||
| std::unique_lock<std::mutex> lk(mu_); | |||
| cv_.wait(lk, [&]() { return is_released_ || is_cancelled_; }); | |||
| return is_released_; | |||
| } | |||
| void NodeDoneManager::Cond::Release() { | |||
| std::unique_lock<std::mutex> lk(cond_mu_); | |||
| std::unique_lock<std::mutex> lk(mu_); | |||
| is_released_ = true; | |||
| cv_.notify_all(); | |||
| } | |||
| void NodeDoneManager::Cond::Cancel() { | |||
| std::unique_lock<std::mutex> lk(cond_mu_); | |||
| std::unique_lock<std::mutex> lk(mu_); | |||
| is_cancelled_ = true; | |||
| cv_.notify_all(); | |||
| } | |||
| bool NodeDoneManager::Cond::IsRelease() { | |||
| std::unique_lock<std::mutex> lk(cond_mu_); | |||
| std::unique_lock<std::mutex> lk(mu_); | |||
| return is_released_; | |||
| } | |||
| NodeDoneManager::Cond *NodeDoneManager::GetSubject(const NodePtr &node) { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| if (destroyed_) { | |||
| GELOGD("Already destroyed."); | |||
| return nullptr; | |||
| } | |||
| auto it = subjects_.find(node); | |||
| if (it == subjects_.end()) { | |||
| return &subjects_[node]; | |||
| @@ -66,10 +52,8 @@ NodeDoneManager::Cond *NodeDoneManager::GetSubject(const NodePtr &node) { | |||
| return &it->second; | |||
| } | |||
| void NodeDoneManager::Destroy() { | |||
| GELOGD("Start to reset NodeDoneManager."); | |||
| void NodeDoneManager::Reset() { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| GELOGD("Cond size = %zu.", subjects_.size()); | |||
| for (auto &sub : subjects_) { | |||
| if (!sub.second.IsRelease()) { | |||
| sub.second.Cancel(); | |||
| @@ -78,24 +62,15 @@ void NodeDoneManager::Destroy() { | |||
| } | |||
| subjects_.clear(); | |||
| destroyed_ = true; | |||
| GELOGD("Done resetting NodeDoneManager successfully."); | |||
| } | |||
| void NodeDoneManager::NodeDone(const NodePtr &node) { | |||
| auto sub = GetSubject(node); | |||
| if (sub != nullptr) { | |||
| sub->Release(); | |||
| GELOGD("[%s] Node released.", node->GetName().c_str()); | |||
| } | |||
| GetSubject(node)->Release(); | |||
| GELOGD("[%s] Node released.", node->GetName().c_str()); | |||
| } | |||
| bool NodeDoneManager::Await(const NodePtr &node) { | |||
| auto sub = GetSubject(node); | |||
| if (sub == nullptr) { | |||
| return false; | |||
| } | |||
| GELOGD("[%s] Await start. is_released = %s", node->GetName().c_str(), sub->IsRelease() ? "true" : "false"); | |||
| bool ret = sub->Await(); | |||
| GELOGD("[%s] Await ended. is_released = %s", node->GetName().c_str(), sub->IsRelease() ? "true" : "false"); | |||
| @@ -31,7 +31,7 @@ class NodeDoneManager { | |||
| bool Await(const NodePtr &node); | |||
| void Destroy(); | |||
| void Reset(); | |||
| private: | |||
| class Cond { | |||
| @@ -42,7 +42,7 @@ class NodeDoneManager { | |||
| bool Await(); | |||
| private: | |||
| std::mutex cond_mu_; | |||
| std::mutex mu_; | |||
| std::condition_variable cv_; | |||
| bool is_released_ = false; | |||
| bool is_cancelled_ = false; | |||
| @@ -51,7 +51,6 @@ class NodeDoneManager { | |||
| Cond *GetSubject(const NodePtr &node); | |||
| std::mutex mu_; | |||
| std::unordered_map<NodePtr, Cond> subjects_; | |||
| bool destroyed_ = false; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -15,133 +15,13 @@ | |||
| */ | |||
| #include "hybrid/executor/node_state.h" | |||
| #include <chrono> | |||
| #include "framework/common/debug/log.h" | |||
| #include "graph/compute_graph.h" | |||
| #include "hybrid_execution_context.h" | |||
| #include "subgraph_context.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr auto kMaxWaitTimeInSec = 10; | |||
| } | |||
| ShapeInferenceState::ShapeInferenceState(const NodeItem &node_item) : node_item(node_item) { | |||
| this->num_pending_shapes_ = node_item.num_inputs - node_item.num_static_input_shapes; | |||
| GELOGD("[%s] ShapeInferenceState created, pending shape count = %d", node_item.NodeName().c_str(), | |||
| this->num_pending_shapes_); | |||
| } | |||
| void ShapeInferenceState::UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape) { | |||
| if (node_item.is_input_shape_static[idx]) { | |||
| GELOGD("[%s] Trying to update static shape, idx = %u. old shape = [%s], new shape = [%s]", | |||
| node_item.NodeName().c_str(), idx, node_item.op_desc->MutableInputDesc(idx)->GetShape().ToString().c_str(), | |||
| shape.ToString().c_str()); | |||
| return; | |||
| } | |||
| GELOGD("[%s] Update input shape [%u] with Shape: [%s] and OriginalShape: [%s]", node_item.NodeName().c_str(), idx, | |||
| shape.ToString().c_str(), ori_shape.ToString().c_str()); | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetShape(shape); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); | |||
| if (--num_pending_shapes_ == 0) { | |||
| ready_cv_.notify_all(); | |||
| } | |||
| } | |||
| void ShapeInferenceState::UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future) { | |||
| if (node_item.is_input_shape_static[idx]) { | |||
| GELOGD("[%s] Trying to update constant shape, idx = %u", node_item.NodeName().c_str(), idx); | |||
| return; | |||
| } | |||
| GELOGD("[%s] Update input shape [%u] with ShapeFuture.", node_item.NodeName().c_str(), idx); | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| shape_futures.emplace_back(idx, std::move(future)); | |||
| if (--num_pending_shapes_ == 0) { | |||
| ready_cv_.notify_all(); | |||
| } | |||
| } | |||
| Status ShapeInferenceState::AwaitShapesReady(const GraphExecutionContext &context) { | |||
| std::unique_lock<std::mutex> lk(mu_); | |||
| if (num_pending_shapes_ > 0) { | |||
| GELOGD("[%s] Await pending shape or shape future start.", node_item.NodeName().c_str()); | |||
| if (!ready_cv_.wait_for(lk, std::chrono::seconds(kMaxWaitTimeInSec), [&]() { return num_pending_shapes_ == 0; })) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Wait for shape timeout.", node_item.NodeName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("[%s] Await pending shape or shape future end.", node_item.NodeName().c_str()); | |||
| } | |||
| for (auto &p : shape_futures) { | |||
| auto idx = p.first; | |||
| auto &future = p.second; | |||
| GeShape shape; | |||
| GeShape ori_shape; | |||
| RECORD_SHAPE_INFERENCE_EVENT(&context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] Start", idx); | |||
| GE_CHK_STATUS_RET(future.Get(ori_shape, shape), "[%s] Get shape failed. index = %u", node_item.NodeName().c_str(), | |||
| idx); | |||
| RECORD_SHAPE_INFERENCE_EVENT(&context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] End", idx); | |||
| GELOGD("[%s] Update input shape [%u] with shape: [%s] and ori_shape: [%s]", node_item.NodeName().c_str(), idx, | |||
| shape.ToString().c_str(), ori_shape.ToString().c_str()); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetShape(std::move(shape)); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| ShapeFuture::ShapeFuture(NodePtr src_node, uint32_t src_index, SubgraphContext *subgraph_context) | |||
| : src_node_(std::move(src_node)), src_index_(src_index), subgraph_context_(subgraph_context) {} | |||
| NodeState::NodeState(const NodeItem &node_item, SubgraphContext *subgraph_context) | |||
| : node_item_(&node_item), shape_inference_state_(node_item), subgraph_context_(subgraph_context) { | |||
| this->op_desc_ = node_item.node->GetOpDesc(); | |||
| } | |||
| Status NodeState::AwaitInputTensors(GraphExecutionContext &context) const { | |||
| for (auto &src_node : node_item_->dependents_for_execution) { | |||
| GELOGI("[%s] Start to wait for data dependent node: [%s]", node_item_->NodeName().c_str(), | |||
| src_node->GetName().c_str()); | |||
| RECORD_EXECUTION_EVENT(&context, node_item_->NodeName().c_str(), "[AwaitNodeDone] [%s] Start", | |||
| src_node->GetName().c_str()); | |||
| if (!subgraph_context_->Await(src_node)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Await node [%s] failed.", GetName().c_str(), src_node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| RECORD_EXECUTION_EVENT(&context, node_item_->NodeName().c_str(), "[AwaitNodeDone] [%s] End", | |||
| src_node->GetName().c_str()); | |||
| GELOGI("[%s] Done waiting node.", src_node->GetName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status NodeState::WaitForPrepareDone() { | |||
| if (prepare_future_.valid()) { | |||
| GELOGD("[%s] Start to wait for prepare future.", GetName().c_str()); | |||
| GE_CHK_STATUS_RET(prepare_future_.get(), "[%s] PreRun failed.", GetName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status ShapeFuture::Get(GeShape &ori_shape, GeShape &shape) { | |||
| GELOGI("Start to wait node: %s for getting shape", src_node_->GetName().c_str()); | |||
| if (!subgraph_context_->Await(src_node_)) { | |||
| GELOGE(INTERNAL_ERROR, "cancelled"); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->MutableShape(); | |||
| ori_shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->GetOriginShape(); | |||
| GELOGI("Get shape from %s:%u. shape = [%s]", src_node_->GetName().c_str(), src_index_, shape.ToString().c_str()); | |||
| return SUCCESS; | |||
| NodeState::NodeState(const NodeItem &node_item) { | |||
| this->node_item = &node_item; | |||
| this->op_desc = node_item.node->GetOpDesc(); | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -17,83 +17,38 @@ | |||
| #ifndef GE_HYBRID_EXECUTOR_NODE_STATE_H_ | |||
| #define GE_HYBRID_EXECUTOR_NODE_STATE_H_ | |||
| #include <condition_variable> | |||
| #include <future> | |||
| #include <mutex> | |||
| #include "external/ge/ge_api_error_codes.h" | |||
| #include "hybrid/model/node_item.h" | |||
| #include "node_done_manager.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class NodeTask; | |||
| class GraphExecutionContext; | |||
| class SubgraphContext; | |||
| class ShapeFuture { | |||
| public: | |||
| ShapeFuture(NodePtr src_node, uint32_t src_index, SubgraphContext *subgraph_context); | |||
| ~ShapeFuture() = default; | |||
| Status Get(GeShape &ori_shape, GeShape &shape); | |||
| private: | |||
| NodePtr src_node_; | |||
| uint32_t src_index_; | |||
| SubgraphContext *subgraph_context_; | |||
| }; | |||
| struct ShapeInferenceState { | |||
| explicit ShapeInferenceState(const NodeItem &node_item); | |||
| void UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape); | |||
| void UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future); | |||
| Status AwaitShapesReady(const GraphExecutionContext &context); | |||
| const NodeItem &node_item; | |||
| private: | |||
| std::vector<std::pair<uint32_t, ShapeFuture>> shape_futures; | |||
| int num_pending_shapes_ = 0; | |||
| std::condition_variable ready_cv_; | |||
| std::mutex mu_; | |||
| }; | |||
| class NodeTask; | |||
| // saving sth. dynamic during execution | |||
| struct NodeState { | |||
| // 存放一些会变化的信息... | |||
| class NodeState { | |||
| public: | |||
| NodeState(const NodeItem &node_item, SubgraphContext *subgraph_context); | |||
| NodeState() = default; | |||
| explicit NodeState(const NodeItem &node_item); | |||
| ~NodeState() = default; | |||
| OpDesc *GetOpDesc() const { return op_desc_.get(); } | |||
| inline const NodeItem *GetNodeItem() const { return node_item_; } | |||
| inline const string &GetName() const { return node_item_->NodeName(); } | |||
| inline const string &GetType() const { return node_item_->NodeType(); } | |||
| inline int NodeId() const { return node_item->node_id; } | |||
| ShapeInferenceState &GetShapeInferenceState() { return shape_inference_state_; } | |||
| inline Node *GetNode() const { return node_item->node.get(); } | |||
| const shared_ptr<NodeTask> &GetKernelTask() const { return kernel_task_; } | |||
| OpDesc *GetOpDesc() const { return op_desc.get(); } | |||
| void SetKernelTask(const shared_ptr<NodeTask> &kernel_task) { kernel_task_ = kernel_task; } | |||
| inline const NodeItem *GetNodeItem() const { return node_item; } | |||
| Status WaitForPrepareDone(); | |||
| inline const string &GetName() const { return node_item->NodeName(); } | |||
| void SetPrepareFuture(std::future<Status> &&prepare_future) { this->prepare_future_ = std::move(prepare_future); } | |||
| inline const string &GetType() const { return node_item->NodeType(); } | |||
| Status AwaitInputTensors(GraphExecutionContext &context) const; | |||
| // private: | |||
| const NodeItem *node_item = nullptr; | |||
| std::shared_ptr<NodeTask> kernel_task = nullptr; | |||
| private: | |||
| const NodeItem *node_item_ = nullptr; | |||
| std::shared_ptr<NodeTask> kernel_task_ = nullptr; | |||
| std::future<Status> prepare_future_; | |||
| OpDescPtr op_desc_; | |||
| ShapeInferenceState shape_inference_state_; | |||
| SubgraphContext *subgraph_context_; | |||
| std::mutex mu_; | |||
| bool is_compiled = false; | |||
| OpDescPtr op_desc; | |||
| }; | |||
| using NodeStatePtr = std::shared_ptr<NodeState>; | |||
| @@ -42,6 +42,7 @@ Status CallbackManager::Init() { | |||
| rtContext_t ctx = nullptr; | |||
| GE_CHK_RT_RET(rtCtxGetCurrent(&ctx)); | |||
| ret_future_ = std::async([&](rtContext_t context) -> Status { return CallbackProcess(context); }, ctx); | |||
| if (!ret_future_.valid()) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to init callback manager."); | |||
| return INTERNAL_ERROR; | |||
| @@ -1,112 +0,0 @@ | |||
| /** | |||
| * 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 "subgraph_context.h" | |||
| #include "common/debug/log.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| SubgraphContext::SubgraphContext(const GraphItem *graph_item) : graph_item_(graph_item) {} | |||
| Status SubgraphContext::Init() { | |||
| GE_CHECK_NOTNULL(graph_item_); | |||
| GELOGD("[%s] Start to init subgraph context. total inputs = %d, total outputs = %d", graph_item_->GetName().c_str(), | |||
| graph_item_->TotalInputs(), graph_item_->TotalOutputs()); | |||
| all_inputs_.resize(graph_item_->TotalInputs()); | |||
| all_outputs_.resize(graph_item_->TotalOutputs()); | |||
| return SUCCESS; | |||
| } | |||
| NodeStatePtr SubgraphContext::GetOrCreateNodeState(const NodeItem *node_item) { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| auto &node_state = node_states_[node_item]; | |||
| if (node_state == nullptr) { | |||
| node_state.reset(new (std::nothrow) NodeState(*node_item, this)); | |||
| } | |||
| return node_state; | |||
| } | |||
| Status SubgraphContext::SetInput(int index, const TensorValue &tensor) { | |||
| if (static_cast<size_t>(index) >= all_inputs_.size()) { | |||
| GELOGE(INTERNAL_ERROR, "output index output range. all input num = %zu, input index = %d", all_inputs_.size(), | |||
| index); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| all_inputs_[index] = tensor; | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphContext::SetInput(const NodeItem &node_item, int input_index, const TensorValue &tensor) { | |||
| auto index = node_item.input_start + input_index; | |||
| return SetInput(index, tensor); | |||
| } | |||
| Status SubgraphContext::SetOutput(const NodeItem &node_item, int output_index, const TensorValue &tensor) { | |||
| auto index = node_item.output_start + output_index; | |||
| if (output_index >= node_item.num_outputs || static_cast<size_t>(index) >= all_outputs_.size()) { | |||
| GELOGE(INTERNAL_ERROR, "output index output range. all output num = %zu, node_item = %s, output index = %d", | |||
| all_outputs_.size(), node_item.DebugString().c_str(), output_index); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| all_outputs_[index] = tensor; | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphContext::GetInput(int index, TensorValue &tensor) { | |||
| GE_CHECK_GE(all_inputs_.size(), index + 1U); | |||
| tensor = all_inputs_[index]; | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphContext::GetOutputs(std::vector<TensorValue> &outputs) { | |||
| if (graph_item_->IsDynamic()) { | |||
| GELOGD("[%s] graph is dynamic, get outputs from net output input tensors", graph_item_->GetName().c_str()); | |||
| // get from net output inputs | |||
| auto output_node = graph_item_->GetOutputNode(); | |||
| GE_CHECK_NOTNULL(output_node); | |||
| for (int i = 0; i < output_node->num_inputs; ++i) { | |||
| TensorValue tensor; | |||
| GE_CHK_STATUS_RET_NOLOG(GetInput(output_node->input_start + i, tensor)); | |||
| GELOGD("[%s] Adding output tensor by input index [%d], tensor = %s", graph_item_->GetName().c_str(), | |||
| output_node->input_start + i, tensor.DebugString().c_str()); | |||
| outputs.emplace_back(std::move(tensor)); | |||
| } | |||
| } else { | |||
| GELOGD("[%s] graph is non-dynamic, get outputs from subgraph outputs", graph_item_->GetName().c_str()); | |||
| for (auto &tensor : all_outputs_) { | |||
| GELOGD("[%s] Adding output tensor: %s", graph_item_->GetName().c_str(), tensor.DebugString().c_str()); | |||
| outputs.emplace_back(tensor); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| bool SubgraphContext::Await(const NodePtr &node) { return node_done_manager_.Await(node); } | |||
| void SubgraphContext::OnError(Status error) { | |||
| GELOGE(error, "[%s] Error occurred while executing graph.", graph_item_->GetName().c_str()); | |||
| node_done_manager_.Destroy(); | |||
| } | |||
| void SubgraphContext::NodeDone(const NodePtr &node) { node_done_manager_.NodeDone(node); } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,61 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ | |||
| #define GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ | |||
| #include <vector> | |||
| #include "hybrid/common/tensor_value.h" | |||
| #include "hybrid/executor/node_state.h" | |||
| #include "hybrid/executor/node_done_manager.h" | |||
| #include "hybrid/model/graph_item.h" | |||
| #include "hybrid/model/node_item.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class SubgraphContext { | |||
| public: | |||
| explicit SubgraphContext(const GraphItem *graph_item); | |||
| ~SubgraphContext() = default; | |||
| Status Init(); | |||
| NodeStatePtr GetOrCreateNodeState(const NodeItem *node_item); | |||
| void OnError(Status error); | |||
| Status SetInput(const NodeItem &node_item, int input_index, const TensorValue &tensor); | |||
| Status SetOutput(const NodeItem &node_item, int output_index, const TensorValue &tensor); | |||
| Status SetInput(int index, const TensorValue &tensor); | |||
| Status GetInput(int index, TensorValue &tensor); | |||
| Status GetOutputs(std::vector<TensorValue> &outputs); | |||
| bool Await(const NodePtr &node); | |||
| void NodeDone(const NodePtr &node); | |||
| private: | |||
| friend class TaskContext; | |||
| const GraphItem *graph_item_; | |||
| std::mutex mu_; | |||
| std::vector<TensorValue> all_inputs_; | |||
| std::vector<TensorValue> all_outputs_; | |||
| NodeDoneManager node_done_manager_; | |||
| std::unordered_map<const NodeItem *, NodeStatePtr> node_states_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ | |||
| @@ -1,373 +0,0 @@ | |||
| /** | |||
| * 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 "hybrid/executor/subgraph_executor.h" | |||
| #include "hybrid/executor/worker/task_compile_engine.h" | |||
| #include "hybrid/executor/worker/execution_engine.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr int kDefaultThreadNum = 4; | |||
| constexpr int kDataInputIndex = 0; | |||
| } // namespace | |||
| SubgraphExecutor::SubgraphExecutor(const GraphItem *graph_item, GraphExecutionContext *context, bool force_infer_shape) | |||
| : graph_item_(graph_item), | |||
| context_(context), | |||
| force_infer_shape_(force_infer_shape), | |||
| pre_run_pool_(kDefaultThreadNum) {} | |||
| SubgraphExecutor::~SubgraphExecutor() { GELOGD("[%s] SubgraphExecutor destroyed.", graph_item_->GetName().c_str()); } | |||
| Status SubgraphExecutor::Init(const std::vector<TensorValue> &inputs, | |||
| const std::vector<ConstGeTensorDescPtr> &input_desc) { | |||
| subgraph_context_.reset(new (std::nothrow) SubgraphContext(graph_item_)); | |||
| GE_CHECK_NOTNULL(subgraph_context_); | |||
| GE_CHK_STATUS_RET(subgraph_context_->Init(), "[%s] Failed to init subgraph context.", graph_item_->GetName().c_str()); | |||
| shape_inference_engine_.reset(new (std::nothrow) ShapeInferenceEngine(context_, subgraph_context_.get())); | |||
| GE_CHECK_NOTNULL(shape_inference_engine_); | |||
| if (graph_item_->IsDynamic()) { | |||
| GE_CHK_STATUS_RET(InitInputsForUnknownShape(inputs, input_desc), "[%s] Failed to set inputs.", | |||
| graph_item_->GetName().c_str()); | |||
| } else { | |||
| GE_CHK_STATUS_RET(InitInputsForKnownShape(inputs), | |||
| "[%s] Failed to init subgraph executor for known shape subgraph.", | |||
| graph_item_->GetName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::InitInputsForUnknownShape(const std::vector<TensorValue> &inputs, | |||
| const std::vector<ConstGeTensorDescPtr> &input_desc) { | |||
| // Number of inputs of parent node should be greater or equal than that of subgraph | |||
| auto input_nodes = graph_item_->GetInputNodes(); | |||
| if (inputs.size() < input_nodes.size()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Number of inputs [%zu] is not sufficient for subgraph which needs [%zu] inputs.", | |||
| graph_item_->GetName().c_str(), inputs.size(), input_nodes.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| for (size_t i = 0; i < input_nodes.size(); ++i) { | |||
| auto &input_node = input_nodes[i]; | |||
| if (input_node == nullptr) { | |||
| GELOGD("[%s] Input[%zu] is not needed by subgraph, skip it.", graph_item_->GetName().c_str(), i); | |||
| continue; | |||
| } | |||
| auto &input_tensor = inputs[i]; | |||
| GELOGD("[%s] Set input tensor[%zu] to inputs with index = %d, tensor = %s", graph_item_->GetName().c_str(), i, | |||
| input_node->input_start, input_tensor.DebugString().c_str()); | |||
| GE_CHK_STATUS_RET(subgraph_context_->SetInput(*input_node, kDataInputIndex, input_tensor), | |||
| "[%s] Failed to set input tensor[%zu]", graph_item_->GetName().c_str(), i); | |||
| if (force_infer_shape_ || input_node->is_dynamic) { | |||
| GELOGD("[%s] Start to update input[%zu] for subgraph data node.", graph_item_->GetName().c_str(), i); | |||
| GE_CHECK_LE(i + 1, input_desc.size()); | |||
| const auto &tensor_desc = input_desc[i]; | |||
| auto node_state = subgraph_context_->GetOrCreateNodeState(input_node); | |||
| GE_CHECK_NOTNULL(node_state); | |||
| node_state->GetShapeInferenceState().UpdateInputShape(0, tensor_desc->GetOriginShape(), tensor_desc->GetShape()); | |||
| } | |||
| } | |||
| GELOGD("[%s] Done setting inputs.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::InitInputsForKnownShape(const std::vector<TensorValue> &inputs) { | |||
| auto &input_index_mapping = graph_item_->GetInputIndexMapping(); | |||
| for (size_t i = 0; i < input_index_mapping.size(); ++i) { | |||
| auto &parent_input_index = input_index_mapping[i]; | |||
| if (static_cast<size_t>(parent_input_index) >= inputs.size()) { | |||
| GELOGE(INTERNAL_ERROR, | |||
| "[%s] Number of inputs [%zu] is not sufficient for subgraph which needs at lease [%d] inputs", | |||
| graph_item_->GetName().c_str(), inputs.size(), parent_input_index + 1); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| auto &input_tensor = inputs[parent_input_index]; | |||
| subgraph_context_->SetInput(i, input_tensor); | |||
| GELOGD("[%s] Set input tensor[%zu] with inputs with index = %d, tensor = %s", graph_item_->GetName().c_str(), i, | |||
| parent_input_index, input_tensor.DebugString().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::ExecuteAsync(const std::vector<TensorValue> &inputs, | |||
| const std::vector<ConstGeTensorDescPtr> &input_desc) { | |||
| GELOGD("[%s] is dynamic = %s", graph_item_->GetName().c_str(), graph_item_->IsDynamic() ? "true" : "false"); | |||
| GE_CHK_STATUS_RET(Init(inputs, input_desc), "[%s] Failed to init executor.", graph_item_->GetName().c_str()); | |||
| if (!graph_item_->IsDynamic()) { | |||
| return ExecuteAsyncForKnownShape(inputs); | |||
| } | |||
| GE_CHK_STATUS_RET(ScheduleTasks(), "[%s] Failed to execute tasks.", graph_item_->GetName().c_str()); | |||
| GELOGD("[%s] Done executing subgraph successfully.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::ExecuteAsyncForKnownShape(const std::vector<TensorValue> &inputs) { | |||
| GELOGD("[%s] subgraph is not dynamic.", graph_item_->GetName().c_str()); | |||
| if (graph_item_->GetAllNodes().size() != 1) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Invalid known shape subgraph. node size = %zu", graph_item_->GetName().c_str(), | |||
| graph_item_->GetAllNodes().size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| auto node_item = graph_item_->GetAllNodes()[0]; | |||
| GE_CHECK_NOTNULL(node_item); | |||
| auto node_state = subgraph_context_->GetOrCreateNodeState(node_item); | |||
| GE_CHECK_NOTNULL(node_state); | |||
| node_state->SetKernelTask(node_item->kernel_task); | |||
| known_shape_task_context_ = TaskContext::Create(*node_item, context_, subgraph_context_.get()); | |||
| GE_CHECK_NOTNULL(known_shape_task_context_); | |||
| GE_CHK_STATUS_RET(ExecutionEngine::ExecuteAsync(*node_state, known_shape_task_context_, *context_), | |||
| "[%s] Failed to execute node [%s] for known subgraph.", graph_item_->GetName().c_str(), | |||
| known_shape_task_context_->GetNodeName()); | |||
| GELOGD("[%s] Done execute non-dynamic subgraph successfully.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::ExecuteAsync(TaskContext &task_context) { | |||
| std::vector<TensorValue> inputs; | |||
| std::vector<ConstGeTensorDescPtr> input_desc; | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| auto tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(tensor); | |||
| inputs.emplace_back(*tensor); | |||
| input_desc.emplace_back(task_context.GetInputDesc(i)); | |||
| } | |||
| GE_CHK_STATUS_RET(ExecuteAsync(inputs, input_desc), "[%s] Failed to execute subgraph.", | |||
| graph_item_->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(SetOutputsToParentNode(task_context), "[%s] Failed to set output shapes to parent node.", | |||
| graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::PrepareNodes() { | |||
| GELOGD("[%s] Start to prepare nodes. force infer shape = %s.", graph_item_->GetName().c_str(), | |||
| force_infer_shape_ ? "true" : "false"); | |||
| auto &all_nodes = graph_item_->GetAllNodes(); | |||
| for (size_t i = 0; i < all_nodes.size(); ++i) { | |||
| auto &node_item = *all_nodes[i]; | |||
| // for while op | |||
| if (force_infer_shape_ && !node_item.is_dynamic) { | |||
| GELOGD("[%s] Force infer shape is set, updating node to dynamic.", node_item.NodeName().c_str()); | |||
| auto &mutable_node_item = const_cast<NodeItem &>(node_item); | |||
| mutable_node_item.SetToDynamic(); | |||
| } | |||
| GELOGD("[%s] Start to prepare node [%s].", graph_item_->GetName().c_str(), node_item.NodeName().c_str()); | |||
| auto node_state = subgraph_context_->GetOrCreateNodeState(&node_item); | |||
| GE_CHECK_NOTNULL(node_state); | |||
| auto p_node_state = node_state.get(); | |||
| if (node_item.node_type == NETOUTPUT) { | |||
| // Wait for all inputs become valid | |||
| // after PrepareNodes returned. all output tensors and shapes are valid | |||
| GE_CHK_STATUS_RET_NOLOG(p_node_state->GetShapeInferenceState().AwaitShapesReady(*context_)); | |||
| GE_CHK_STATUS_RET_NOLOG(p_node_state->AwaitInputTensors(*context_)); | |||
| continue; | |||
| } | |||
| // only do shape inference and compilation for nodes with dynamic shapes. | |||
| if (node_item.is_dynamic) { | |||
| auto prepare_future = pre_run_pool_.commit([this, p_node_state]() -> Status { | |||
| GE_CHK_STATUS_RET_NOLOG(InferShape(shape_inference_engine_.get(), *p_node_state)); | |||
| return PrepareForExecution(context_, *p_node_state); | |||
| }); | |||
| p_node_state->SetPrepareFuture(std::move(prepare_future)); | |||
| } else { | |||
| GELOGD("[%s] Skipping shape inference and compilation for node with static shape.", node_item.NodeName().c_str()); | |||
| if (node_item.kernel_task == nullptr) { | |||
| GELOGW("[%s] Node of static shape got no task.", node_item.NodeName().c_str()); | |||
| GE_CHK_STATUS_RET(TaskCompileEngine::Compile(*p_node_state, context_), "[%s] Failed to create task.", | |||
| p_node_state->GetName().c_str()); | |||
| } else { | |||
| node_state->SetKernelTask(node_item.kernel_task); | |||
| } | |||
| } | |||
| if (!ready_queue_.Push(p_node_state)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Error occurs while launching tasks. quit from preparing nodes.", | |||
| graph_item_->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("[%s] Push node [%s] to queue.", graph_item_->GetName().c_str(), node_item.NodeName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::InferShape(ShapeInferenceEngine *shape_inference_engine, NodeState &node_state) { | |||
| const auto &node_item = *node_state.GetNodeItem(); | |||
| GE_CHK_STATUS_RET(shape_inference_engine->InferShape(node_state), "[%s] Failed to InferShape.", | |||
| node_state.GetName().c_str()); | |||
| GE_CHK_STATUS_RET(shape_inference_engine->PropagateOutputShapes(node_item), "[%s] Failed to PropagateOutputShapes.", | |||
| node_state.GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::PrepareForExecution(GraphExecutionContext *ctx, NodeState &node_state) { | |||
| auto &node_item = *node_state.GetNodeItem(); | |||
| if (node_item.kernel_task == nullptr) { | |||
| GE_CHK_STATUS_RET(TaskCompileEngine::Compile(node_state, ctx), "Failed to create task for node[%s]", | |||
| node_state.GetName().c_str()); | |||
| } else { | |||
| node_state.SetKernelTask(node_item.kernel_task); | |||
| } | |||
| GELOGD("[%s] Start to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); | |||
| RECORD_COMPILE_EVENT(ctx, node_item.NodeName().c_str(), "[CalcOpRunningParam] Start"); | |||
| GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().CalcOpRunningParam(*node_item.node), | |||
| "[%s] Failed to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); | |||
| RECORD_COMPILE_EVENT(ctx, node_item.NodeName().c_str(), "[CalcOpRunningParam] End"); | |||
| GELOGD("[%s] Done invoking CalcOpRunningParam successfully.", node_item.NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::LaunchTasks() { | |||
| while (true) { | |||
| NodeState *node_state = nullptr; | |||
| if (!ready_queue_.Pop(node_state)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Failed to pop node.", graph_item_->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| if (node_state == nullptr) { | |||
| GELOGD("[%s] Got EOF from queue.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| GE_CHK_STATUS_RET_NOLOG(node_state->WaitForPrepareDone()); | |||
| GELOGD("[%s] Start to execute.", node_state->GetName().c_str()); | |||
| auto task_context = TaskContext::Create(*node_state->GetNodeItem(), context_, subgraph_context_.get()); | |||
| GE_CHECK_NOTNULL(task_context); | |||
| task_context->SetForceInferShape(force_infer_shape_); | |||
| auto shared_task_context = std::shared_ptr<TaskContext>(task_context.release()); | |||
| GE_CHK_STATUS_RET(ExecutionEngine::ExecuteAsync(*node_state, shared_task_context, *context_), | |||
| "[%s] Execute node failed.", node_state->GetName().c_str()); | |||
| GELOGD("[%s] Done executing node successfully.", node_state->GetName().c_str()); | |||
| } | |||
| } | |||
| Status SubgraphExecutor::ScheduleTasks() { | |||
| GELOGD("[%s] Start to schedule prepare workers.", graph_item_->GetName().c_str()); | |||
| auto prepare_future = std::async([&]() -> Status { | |||
| auto ret = PrepareNodes(); | |||
| ready_queue_.Push(nullptr); | |||
| return ret; | |||
| }); | |||
| GELOGD("[%s] Start to execute subgraph.", graph_item_->GetName().c_str()); | |||
| auto ret = LaunchTasks(); | |||
| if (ret != SUCCESS) { | |||
| GELOGE(ret, "[%s] Failed to execute subgraph.", graph_item_->GetName().c_str()); | |||
| subgraph_context_->OnError(ret); | |||
| ready_queue_.Stop(); | |||
| prepare_future.wait(); | |||
| return ret; | |||
| } | |||
| GE_CHK_STATUS_RET(prepare_future.get(), "[%s] Error occurred in task preparation.", graph_item_->GetName().c_str()); | |||
| GELOGD("[%s] Done launching all tasks successfully.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::GetOutputs(vector<TensorValue> &outputs) { return subgraph_context_->GetOutputs(outputs); } | |||
| Status SubgraphExecutor::GetOutputs(vector<TensorValue> &outputs, std::vector<ConstGeTensorDescPtr> &output_desc) { | |||
| GE_CHK_STATUS_RET(GetOutputs(outputs), "[%s] Failed to get output tensors.", graph_item_->GetName().c_str()); | |||
| // copy output data from op to designated position | |||
| std::vector<GeTensorDescPtr> output_tensor_desc_list; | |||
| GE_CHK_STATUS_RET(graph_item_->GetOutputDescList(output_desc), "[%s] Failed to get output tensor desc.", | |||
| graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::Synchronize() { | |||
| GELOGD("[%s] Synchronize start.", graph_item_->GetName().c_str()); | |||
| GE_CHK_RT_RET(rtStreamSynchronize(context_->stream)); | |||
| GELOGD("[%s] Done synchronizing successfully.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status SubgraphExecutor::SetOutputsToParentNode(TaskContext &task_context) { | |||
| // get output tensors and tensor desc list | |||
| std::vector<TensorValue> outputs; | |||
| std::vector<ConstGeTensorDescPtr> output_desc_list; | |||
| GE_CHK_STATUS_RET(subgraph_context_->GetOutputs(outputs), "[%s] Failed to get output tensors.", | |||
| graph_item_->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(graph_item_->GetOutputDescList(output_desc_list), "[%s] Failed to get output tensor desc.", | |||
| graph_item_->GetName().c_str()); | |||
| if (outputs.size() != output_desc_list.size()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] num output tensors = %zu, num output tensor desc = %zu", | |||
| graph_item_->GetName().c_str(), outputs.size(), output_desc_list.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| // mapping to parent task context | |||
| for (size_t i = 0; i < outputs.size(); ++i) { | |||
| int parent_output_index = graph_item_->GetParentOutputIndex(i); | |||
| GE_CHECK_GE(parent_output_index, 0); | |||
| // update tensor | |||
| GELOGD("[%s] Updating output[%zu] to parent output[%d]", graph_item_->GetName().c_str(), i, parent_output_index); | |||
| GELOGD("[%s] Updating output tensor, index = %d, tensor = %s", graph_item_->GetName().c_str(), parent_output_index, | |||
| outputs[i].DebugString().c_str()); | |||
| task_context.SetOutput(parent_output_index, outputs[i]); | |||
| // updating shapes. dynamic format/dtype is not supported. | |||
| // It should be noted that even the subgraph is of known shape, it is also necessary to update parent output desc, | |||
| // for instance, IfOp may have two known-shaped subgraphs of different output shapes | |||
| const auto &output_desc = output_desc_list[i]; | |||
| auto parent_output_desc = task_context.MutableOutputDesc(parent_output_index); | |||
| GE_CHECK_NOTNULL(parent_output_desc); | |||
| GELOGD("[%s] Updating output shape[%d] from [%s] to [%s]", graph_item_->GetName().c_str(), parent_output_index, | |||
| parent_output_desc->MutableShape().ToString().c_str(), output_desc->GetShape().ToString().c_str()); | |||
| parent_output_desc->SetShape(output_desc->GetShape()); | |||
| GELOGD("[%s] Updating output original shape[%d] from [%s] to [%s]", graph_item_->GetName().c_str(), | |||
| parent_output_index, parent_output_desc->GetOriginShape().ToString().c_str(), | |||
| output_desc->GetOriginShape().ToString().c_str()); | |||
| parent_output_desc->SetOriginShape(output_desc->GetOriginShape()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,101 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ | |||
| #define GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ | |||
| #include <vector> | |||
| #include "common/blocking_queue.h" | |||
| #include "common/thread_pool.h" | |||
| #include "hybrid/executor/subgraph_context.h" | |||
| #include "hybrid/executor/node_state.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/worker/shape_inference_engine.h" | |||
| #include "hybrid/model/graph_item.h" | |||
| #include "hybrid/node_executor/task_context.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| // Executor for executing a subgraph | |||
| class SubgraphExecutor { | |||
| public: | |||
| SubgraphExecutor(const GraphItem *graph_item, GraphExecutionContext *context, bool force_infer_shape = false); | |||
| ~SubgraphExecutor(); | |||
| /** | |||
| * Execute subgraph async, output tensor address(not data) and output tensor descriptions are | |||
| * valid after this method returned | |||
| * @param inputs input tensors | |||
| * @param input_desc input tensor descriptions | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status ExecuteAsync(const std::vector<TensorValue> &inputs, const std::vector<ConstGeTensorDescPtr> &input_desc); | |||
| /** | |||
| * Execute subgraph async, output tensor address(not data) and output tensor descriptions are | |||
| * valid after this method returned | |||
| * @param task_context instance of TaskContext | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status ExecuteAsync(TaskContext &task_context); | |||
| /** | |||
| * Synchronize all tasks in the subgraph. output tensor data are valid after this method returned | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status Synchronize(); | |||
| /** | |||
| * Get output tensors | |||
| * @param outputs output tensors | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status GetOutputs(std::vector<TensorValue> &outputs); | |||
| /** | |||
| * Get output tensors and output tensor descriptions | |||
| * @param outputs output tensors | |||
| * @param output_desc output tensor descriptions | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status GetOutputs(std::vector<TensorValue> &outputs, std::vector<ConstGeTensorDescPtr> &output_desc); | |||
| private: | |||
| static Status PrepareForExecution(GraphExecutionContext *ctx, NodeState &node_state); | |||
| static Status InferShape(ShapeInferenceEngine *shape_inference_engine, NodeState &node_state); | |||
| Status Init(const std::vector<TensorValue> &inputs, const std::vector<ConstGeTensorDescPtr> &input_desc); | |||
| Status InitInputsForUnknownShape(const std::vector<TensorValue> &inputs, | |||
| const std::vector<ConstGeTensorDescPtr> &input_desc); | |||
| Status InitInputsForKnownShape(const std::vector<TensorValue> &inputs); | |||
| Status ExecuteAsyncForKnownShape(const std::vector<TensorValue> &inputs); | |||
| Status ScheduleTasks(); | |||
| Status PrepareNodes(); | |||
| Status LaunchTasks(); | |||
| Status SetOutputsToParentNode(TaskContext &task_context); | |||
| const GraphItem *graph_item_; | |||
| GraphExecutionContext *context_; | |||
| std::unique_ptr<SubgraphContext> subgraph_context_; | |||
| bool force_infer_shape_; | |||
| ThreadPool pre_run_pool_; | |||
| BlockingQueue<NodeState *> ready_queue_; | |||
| std::unique_ptr<ShapeInferenceEngine> shape_inference_engine_; | |||
| std::shared_ptr<TaskContext> known_shape_task_context_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ | |||
| @@ -15,6 +15,7 @@ | |||
| */ | |||
| #include "hybrid/executor/worker/execution_engine.h" | |||
| #include <sstream> | |||
| #include "graph/runtime_inference_context.h" | |||
| #include "graph/utils/tensor_utils.h" | |||
| #include "graph/utils/tensor_adapter.h" | |||
| @@ -22,38 +23,9 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr int64_t kMaxPadding = 63; | |||
| Status LogInputs(const NodeItem &node_item, const TaskContext &task_context) { | |||
| for (auto i = 0; i < task_context.NumInputs(); ++i) { | |||
| const auto &input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| const auto &tensor_desc = node_item.op_desc->MutableInputDesc(i); | |||
| GE_CHECK_NOTNULL(tensor_desc); | |||
| GELOGD("[%s] Print task args. input[%d] = %s, shape = [%s]", node_item.NodeName().c_str(), i, | |||
| input_tensor->DebugString().c_str(), tensor_desc->MutableShape().ToString().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status LogOutputs(const NodeItem &node_item, const TaskContext &task_context) { | |||
| for (auto i = 0; i < task_context.NumOutputs(); ++i) { | |||
| const auto &output_tensor = task_context.GetOutput(i); | |||
| GE_CHECK_NOTNULL(output_tensor); | |||
| const auto &tensor_desc = node_item.op_desc->MutableOutputDesc(i); | |||
| GE_CHECK_NOTNULL(tensor_desc); | |||
| GELOGD("[%s] Print task args. output[%d] = %s, shape = [%s]", node_item.NodeName().c_str(), i, | |||
| output_tensor->DebugString().c_str(), tensor_desc->MutableShape().ToString().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| } // namespace | |||
| class NodeDoneCallback { | |||
| public: | |||
| NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr<TaskContext> task_context); | |||
| NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr<TaskContext> &task_context); | |||
| ~NodeDoneCallback() = default; | |||
| Status OnNodeDone(); | |||
| @@ -63,8 +35,8 @@ class NodeDoneCallback { | |||
| std::shared_ptr<TaskContext> context_; | |||
| }; | |||
| NodeDoneCallback::NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr<TaskContext> task_context) | |||
| : graph_context_(graph_context), context_(std::move(task_context)) {} | |||
| NodeDoneCallback::NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr<TaskContext> &task_context) | |||
| : graph_context_(graph_context), context_(task_context) {} | |||
| Status NodeDoneCallback::PrepareConstInputs(const NodeItem &node_item) { | |||
| for (auto output_idx : node_item.to_const_output_id_list) { | |||
| @@ -74,28 +46,17 @@ Status NodeDoneCallback::PrepareConstInputs(const NodeItem &node_item) { | |||
| auto output_tensor = context_->GetOutput(output_idx); | |||
| GE_CHECK_NOTNULL(output_tensor); | |||
| vector<uint8_t> host_buffer(output_tensor->GetSize()); | |||
| GELOGD("[%s] To cache output[%d] to host, size = %zu", node_item.NodeName().c_str(), output_idx, | |||
| output_tensor->GetSize()); | |||
| GE_CHK_RT_RET(rtMemcpy(host_buffer.data(), host_buffer.size(), output_tensor->GetData(), output_tensor->GetSize(), | |||
| RT_MEMCPY_HOST_TO_DEVICE)); | |||
| Tensor tensor; | |||
| tensor.SetData(host_buffer); | |||
| auto ge_tensor_desc = node_item.op_desc->MutableOutputDesc(output_idx); | |||
| GE_CHECK_NOTNULL(ge_tensor_desc); | |||
| tensor.SetTensorDesc(TensorAdapter::GeTensorDesc2TensorDesc(*ge_tensor_desc)); | |||
| int64_t tensor_size; | |||
| GE_CHK_GRAPH_STATUS_RET(TensorUtils::GetTensorSizeInBytes(*ge_tensor_desc, tensor_size), | |||
| "Failed to invoke GetTensorSizeInBytes"); | |||
| if (output_tensor->GetSize() < static_cast<size_t>(tensor_size)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Tensor size is not enough. output index = %d, required size = %zu, tensor = %s", | |||
| node_item.NodeName().c_str(), output_idx, tensor_size, output_tensor->DebugString().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| vector<uint8_t> host_buffer(tensor_size); | |||
| GELOGD("[%s] To cache output[%d] to host, size = %zu", node_item.NodeName().c_str(), output_idx, | |||
| output_tensor->GetSize()); | |||
| GE_CHK_RT_RET( | |||
| rtMemcpy(host_buffer.data(), tensor_size, output_tensor->GetData(), tensor_size, RT_MEMCPY_DEVICE_TO_HOST)); | |||
| tensor.SetData(host_buffer); | |||
| string session_id = std::to_string(context_->GetSessionId()); | |||
| RuntimeInferenceContext *runtime_infer_ctx = nullptr; | |||
| GE_CHK_GRAPH_STATUS_RET(RuntimeInferenceContext::GetContext(session_id, &runtime_infer_ctx), | |||
| @@ -126,118 +87,115 @@ Status NodeDoneCallback::OnNodeDone() { | |||
| GE_CHK_STATUS_RET_NOLOG(PrepareConstInputs(node_item)); | |||
| // PropagateOutputs for type == DEPEND_COMPUTE | |||
| if (node_item.shape_inference_type == DEPEND_COMPUTE) { | |||
| if (graph_context_->trace_enabled) { | |||
| (void)LogOutputs(node_item, *context_); | |||
| } | |||
| GE_CHK_STATUS_RET(context_->PropagateOutputs(), "[%s] Failed to propagate outputs failed", | |||
| node_item.NodeName().c_str()); | |||
| RECORD_CALLBACK_EVENT(graph_context_, context_->GetNodeName(), "[PropagateOutputs] End"); | |||
| } | |||
| // release condition variable | |||
| // release | |||
| if (node_item.has_observer) { | |||
| GELOGI("[%s] Notify observer. node_id = %d", node_item.NodeName().c_str(), node_item.node_id); | |||
| context_->NodeDone(); | |||
| graph_context_->cv_manager.NodeDone(node_item.node); | |||
| } | |||
| RECORD_CALLBACK_EVENT(graph_context_, context_->GetNodeName(), "[Callback] End"); | |||
| return SUCCESS; | |||
| } | |||
| Status ExecutionEngine::ExecuteAsync(NodeState &node_state, const std::shared_ptr<TaskContext> &task_context, | |||
| GraphExecutionContext &execution_context) { | |||
| GELOGI("[%s] Node is ready for execution", task_context->GetNodeName()); | |||
| RECORD_EXECUTION_EVENT(&execution_context, task_context->GetNodeName(), "Start"); | |||
| auto cb = std::shared_ptr<NodeDoneCallback>(new (std::nothrow) NodeDoneCallback(&execution_context, task_context)); | |||
| GE_CHECK_NOTNULL(cb); | |||
| auto callback = [&, cb]() { | |||
| auto ret = cb->OnNodeDone(); | |||
| if (ret != SUCCESS) { | |||
| task_context->OnError(ret); | |||
| ExecutionEngine::ExecutionEngine(GraphExecutionContext *context, CallbackManager *callback_manager) | |||
| : context_(context), callback_manager_(callback_manager) {} | |||
| Status ExecutionEngine::Start() { | |||
| GE_CHK_STATUS_RET_NOLOG(ExecutionProcess()); | |||
| return SUCCESS; | |||
| } | |||
| Status ExecutionEngine::ExecutionProcess() { | |||
| GELOGI("ExecutorEngine worker started"); | |||
| auto &ready_queue = context_->execution_queue; | |||
| while (true) { | |||
| NodeStatePtr node_state = nullptr; | |||
| if (!ready_queue.Pop(node_state)) { | |||
| GELOGE(FAILED, "Pop task failed"); | |||
| return FAILED; | |||
| } | |||
| // EOF | |||
| if (node_state == nullptr) { | |||
| break; | |||
| } | |||
| }; | |||
| GE_CHK_STATUS_RET_NOLOG(DoExecuteAsync(node_state, *task_context, execution_context, callback)); | |||
| GE_CHK_STATUS_RET_NOLOG(PropagateOutputs(*node_state.GetNodeItem(), *task_context, execution_context)); | |||
| RECORD_EXECUTION_EVENT(context_, node_state->GetName().c_str(), "Start"); | |||
| GELOGI("[%s] Node is ready for execution", node_state->GetName().c_str()); | |||
| auto *node_item = node_state->node_item; | |||
| auto task_context = TaskContext::Create(*node_item, context_); | |||
| GE_CHECK_NOTNULL(task_context); | |||
| auto shared_task_context = shared_ptr<TaskContext>(task_context.release()); | |||
| auto cb = std::shared_ptr<NodeDoneCallback>(new (std::nothrow) NodeDoneCallback(context_, shared_task_context)); | |||
| GE_CHECK_NOTNULL(cb); | |||
| auto callback = [&, cb]() { | |||
| auto ret = cb->OnNodeDone(); | |||
| if (ret != SUCCESS) { | |||
| context_->OnError(ret); | |||
| } | |||
| }; | |||
| GE_CHK_STATUS_RET_NOLOG(ExecuteAsync(*node_state, *shared_task_context, callback)); | |||
| GE_CHK_STATUS_RET_NOLOG(PropagateOutputs(*node_item, *shared_task_context)); | |||
| } | |||
| GELOGI("ExecutorEngine worker ended."); | |||
| return SUCCESS; | |||
| } | |||
| Status ExecutionEngine::DoExecuteAsync(NodeState &node_state, TaskContext &task_context, GraphExecutionContext &context, | |||
| const std::function<void()> &callback) { | |||
| const auto &task = node_state.GetKernelTask(); | |||
| Status ExecutionEngine::ExecuteAsync(NodeState &node_state, TaskContext &task_context, | |||
| const std::function<void()> &callback) { | |||
| const auto &task = node_state.kernel_task; | |||
| if (task == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] NodeTask is null.", node_state.GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| // Wait for dependent nodes(DEPEND_COMPUTE), so that the input tensors are valid. | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[AwaitDependents] Start"); | |||
| GE_CHK_STATUS_RET(node_state.AwaitInputTensors(context), "[%s] Failed to wait for dependent nodes.", | |||
| node_state.GetName().c_str()); | |||
| const auto &node_item = *node_state.GetNodeItem(); | |||
| auto executor = node_item.node_executor; | |||
| GE_CHECK_NOTNULL(executor); | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PrepareTask] Start"); | |||
| RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PrepareTask] Start"); | |||
| auto executor = node_state.node_item->node_executor; | |||
| GE_CHK_STATUS_RET(executor->PrepareTask(*task, task_context), "[%s] Failed to prepare task", | |||
| node_state.GetName().c_str()); | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PrepareTask] End"); | |||
| RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PrepareTask] End"); | |||
| GELOGD("[%s] Done task preparation successfully.", node_state.GetName().c_str()); | |||
| if (context.trace_enabled) { | |||
| LogInputs(node_item, task_context); | |||
| if (node_item.shape_inference_type != DEPEND_COMPUTE) { | |||
| LogOutputs(node_item, task_context); | |||
| if (context_->trace_enabled) { | |||
| for (auto i = 0; i < task_context.NumInputs(); ++i) { | |||
| const auto &input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| GELOGD("[%s] Tensor of input[%d] = %s", node_state.GetName().c_str(), i, input_tensor->DebugString().c_str()); | |||
| } | |||
| } | |||
| GE_CHK_STATUS_RET(ValidateInputTensors(node_state, task_context), "Failed to validate input tensors."); | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[ValidateInputTensors] End"); | |||
| for (auto i = 0; i < task_context.NumOutputs(); ++i) { | |||
| const auto &output_tensor = task_context.GetOutput(i); | |||
| GE_CHECK_NOTNULL(output_tensor); | |||
| GELOGD("[%s] Tensor of output[%d] = %s", node_state.GetName().c_str(), i, output_tensor->DebugString().c_str()); | |||
| } | |||
| } | |||
| RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[ExecuteTask] Start"); | |||
| GE_CHK_STATUS_RET(executor->ExecuteTask(*task, task_context, callback), "[%s] Failed to execute task", | |||
| node_state.GetName().c_str()); | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[ExecuteTask] End"); | |||
| RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[ExecuteTask] End"); | |||
| GELOGD("[%s] Done task launch successfully.", node_state.GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status ExecutionEngine::ValidateInputTensors(const NodeState &node_state, const TaskContext &task_context) { | |||
| for (auto i = 0; i < task_context.NumInputs(); ++i) { | |||
| const auto &input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| const auto &tensor_desc = node_state.GetOpDesc()->MutableInputDesc(i); | |||
| GE_CHECK_NOTNULL(tensor_desc); | |||
| int64_t expected_size; | |||
| GE_CHK_GRAPH_STATUS_RET(TensorUtils::GetTensorMemorySizeInBytes(*tensor_desc, expected_size)); | |||
| GELOGD("[%s] Input[%d] expects [%ld] bytes.", task_context.GetNodeName(), i, expected_size); | |||
| auto size_diff = expected_size - static_cast<int64_t>(input_tensor->GetSize()); | |||
| if (size_diff > 0) { | |||
| if (size_diff <= kMaxPadding) { | |||
| GELOGW("[%s] Input[%d]: tensor size mismatches. expected: %ld, but given %zu", task_context.GetNodeName(), i, | |||
| expected_size, input_tensor->GetSize()); | |||
| } else { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Input[%d]: tensor size mismatches. expected: %ld, but given %zu", | |||
| task_context.GetNodeName(), i, expected_size, input_tensor->GetSize()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status ExecutionEngine::PropagateOutputs(const NodeItem &node_item, TaskContext &task_context, | |||
| GraphExecutionContext &context) { | |||
| Status ExecutionEngine::PropagateOutputs(const NodeItem &node_item, TaskContext &task_context) { | |||
| if (node_item.shape_inference_type != DEPEND_COMPUTE) { | |||
| GE_CHK_STATUS_RET(task_context.PropagateOutputs(), "[%s] Failed to propagate outputs.", | |||
| node_item.NodeName().c_str()); | |||
| RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PropagateOutputs] End"); | |||
| GELOGD("[%s] Done propagating outputs successfully.", node_item.NodeName().c_str()); | |||
| RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PropagateOutputs] End"); | |||
| } | |||
| GELOGD("[%s] Done propagating outputs successfully.", node_item.NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| @@ -17,21 +17,30 @@ | |||
| #ifndef GE_HYBRID_EXECUTOR_EXECUTOR_EXECUTION_ENGINE_H_ | |||
| #define GE_HYBRID_EXECUTOR_EXECUTOR_EXECUTION_ENGINE_H_ | |||
| #include "common/thread_pool.h" | |||
| #include "hybrid/common/npu_memory_allocator.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/rt_callback_manager.h" | |||
| #include "hybrid/node_executor/task_context.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class ExecutionEngine { | |||
| public: | |||
| static Status ExecuteAsync(NodeState &node_state, const std::shared_ptr<TaskContext> &task_context, | |||
| GraphExecutionContext &execution_context); | |||
| explicit ExecutionEngine(GraphExecutionContext *context, CallbackManager *callback_manager); | |||
| ~ExecutionEngine() = default; | |||
| Status Start(); | |||
| private: | |||
| static Status ValidateInputTensors(const NodeState &node_state, const TaskContext &task_context); | |||
| static Status PropagateOutputs(const NodeItem &node_item, TaskContext &task_context, GraphExecutionContext &context); | |||
| static Status DoExecuteAsync(NodeState &node_state, TaskContext &task_context, GraphExecutionContext &context, | |||
| const std::function<void()> &callback); | |||
| Status PropagateOutputs(const NodeItem &node_item, TaskContext &task_context); | |||
| Status ExecutionProcess(); | |||
| Status ExecuteAsync(NodeState &node_state, TaskContext &task_context, const std::function<void()> &callback); | |||
| GraphExecutionContext *context_; | |||
| CallbackManager *callback_manager_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -15,27 +15,117 @@ | |||
| */ | |||
| #include "hybrid/executor/worker/shape_inference_engine.h" | |||
| #include "graph/shape_refiner.h" | |||
| #include "graph/runtime_inference_context.h" | |||
| #include "graph/utils/node_utils.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| ShapeInferenceEngine::ShapeInferenceEngine(GraphExecutionContext *execution_context, SubgraphContext *subgraph_context) | |||
| : execution_context_(execution_context), subgraph_context_(subgraph_context) {} | |||
| Status ShapeInferenceEngine::InferShape(NodeState &node_state) { | |||
| // Wait for all input shape become valid | |||
| GE_CHK_STATUS_RET_NOLOG(node_state.GetShapeInferenceState().AwaitShapesReady(*execution_context_)); | |||
| ShapeInferenceEngine::ShapeInferenceEngine(GraphExecutionContext *context) : context_(context) {} | |||
| Status ShapeInferenceEngine::Start(ThreadPool &pool) { | |||
| GELOGI("RuntimeShapeInferenceEngine start."); | |||
| pool.commit([&]() { | |||
| auto ret = this->InferShapeProcess(); | |||
| InferenceDone(ret); | |||
| }); | |||
| return SUCCESS; | |||
| } | |||
| Status ShapeInferenceEngine::InferShapeProcess() { | |||
| GELOGI("RuntimeShapeInferenceEngine worker start."); | |||
| const auto &root_nodes = context_->model->RootNodes(); | |||
| auto &complete_queue = context_->compile_queue; | |||
| std::queue<InferenceState *> ready_nodes; | |||
| for (auto &node_item : root_nodes) { | |||
| auto infer_state = GetOrCreateEntry(*node_item); | |||
| GE_CHECK_NOTNULL(infer_state); | |||
| ready_nodes.emplace(infer_state); | |||
| } | |||
| while (!ready_nodes.empty()) { | |||
| InferenceState *infer_state = ready_nodes.front(); | |||
| ready_nodes.pop(); | |||
| auto node_item = infer_state->node_item; | |||
| // even for non-dynamic shape node, it is still necessary to wait for pending shapes if got any. | |||
| // which indicates that the parent node is of type 4, in which case the inputs will be valid only | |||
| // when computing is done. | |||
| GE_CHK_STATUS_RET(infer_state->AwaitShapeFutures(context_), "Await shape failed."); | |||
| GELOGI("[%s] Node is ready for shape inference.", node_item.NodeName().c_str()); | |||
| if (node_item.is_dynamic) { | |||
| // may block | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "Start"); | |||
| GELOGI("[%s] Start to invoke InferShape", node_item.NodeName().c_str()); | |||
| auto ret = InferShape(*infer_state); | |||
| if (ret != SUCCESS) { | |||
| return ret; | |||
| } | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[CalcOpRunningParam] Start"); | |||
| GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().CalcOpRunningParam(*node_item.node), | |||
| "[%s] Failed to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[CalcOpRunningParam] End"); | |||
| } else { | |||
| GELOGD("[%s] Skip static shape node", node_item.NodeName().c_str()); | |||
| } | |||
| if (node_item.node_type != NETOUTPUT) { | |||
| GELOGI("[%s] Push to compile queue", node_item.NodeName().c_str()); | |||
| // may block if full | |||
| auto node_state = context_->GetOrCreateNodeState(node_item.node); | |||
| complete_queue.Push(node_state); | |||
| } | |||
| // Propagate | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[PropagateOutputShapes] Start"); | |||
| PropagateOutputShapes(*infer_state, ready_nodes); | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[PropagateOutputShapes] End"); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| void ShapeInferenceEngine::InferenceDone(Status status) { | |||
| if (status != SUCCESS) { | |||
| GELOGE(status, "Error occurred while shape inference"); | |||
| context_->OnError(status); | |||
| } else { | |||
| context_->compile_queue.Push(nullptr); | |||
| } | |||
| inference_states_.clear(); | |||
| GELOGI("RuntimeShapeInferenceEngine worker END"); | |||
| } | |||
| Status ShapeInferenceEngine::InferShape(InferenceState &entry) { | |||
| // input shapes are ready, wait for dependent data if has any | |||
| const auto &node_item = entry.node_item; | |||
| if (!node_item.dependent_node_list.empty()) { | |||
| for (auto &src_node : node_item.dependent_node_list) { | |||
| auto *src_node_item = context_->model->GetNodeItem(src_node); | |||
| GELOGI("[%s] Start to wait for data dependent node: %s", node_item.NodeName().c_str(), | |||
| src_node_item->NodeName().c_str()); | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] Start", | |||
| src_node->GetName().c_str()); | |||
| if (!context_->cv_manager.Await(src_node)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Await node failed.", src_node_item->NodeName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] End", | |||
| src_node->GetName().c_str()); | |||
| GELOGI("[%s] Done waiting node.", src_node_item->NodeName().c_str()); | |||
| } | |||
| } | |||
| auto &node_item = *node_state.GetNodeItem(); | |||
| // Skip shape inference for node of type DEPEND_COMPUTE | |||
| if (node_item.shape_inference_type == DEPEND_COMPUTE) { | |||
| GELOGD("[%s] Skipping node with unknown shape type DEPEND_COMPUTE", node_item.NodeName().c_str()); | |||
| GELOGD("[%s] Skip node with unknown shape type DEPEND_COMPUTE", node_item.NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| // Clear shape range in case shape inference func forgot to do it | |||
| if (node_item.shape_inference_type == DEPEND_SHAPE_RANGE) { | |||
| // in case InferFunc forgot to reset output shape | |||
| for (auto &output_desc : node_item.op_desc->GetAllOutputsDescPtr()) { | |||
| @@ -43,16 +133,13 @@ Status ShapeInferenceEngine::InferShape(NodeState &node_state) { | |||
| } | |||
| } | |||
| // Wait for "const input nodes" if node's shape inference function requires any. | |||
| GE_CHK_STATUS_RET_NOLOG(AwaitDependentNodes(node_state)); | |||
| // Do shape inference | |||
| // do shape inference | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[InferShape] Start"); | |||
| GELOGD("[%s] Start to invoke InferShapeAndType", node_item.NodeName().c_str()); | |||
| RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[InferShapeAndType] Start"); | |||
| GE_CHK_STATUS_RET(ShapeRefiner::InferShapeAndType(node_item.node), "Invoke InferShapeAndType failed."); | |||
| RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[InferShapeAndType] End"); | |||
| RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[InferShape] End"); | |||
| // Check again to make sure shape is valid after shape inference | |||
| // Check shape | |||
| if (node_item.shape_inference_type != DEPEND_SHAPE_RANGE) { | |||
| bool is_unknown_shape = false; | |||
| GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node_item.node, is_unknown_shape), | |||
| @@ -62,33 +149,12 @@ Status ShapeInferenceEngine::InferShape(NodeState &node_state) { | |||
| node_item.NodeName().c_str()); | |||
| } | |||
| GELOGD("[%s] [HybridTrace] After shape inference. Node = %s", node_item.NodeName().c_str(), | |||
| node_item.DebugString().c_str()); | |||
| GELOGD("[%s] InferShapeAndType finished successfully.", node_item.NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status ShapeInferenceEngine::AwaitDependentNodes(NodeState &node_state) { | |||
| auto &node_item = *node_state.GetNodeItem(); | |||
| for (auto &src_node : node_item.dependents_for_shape_inference) { | |||
| GELOGI("[%s] Start to wait for data dependent node: %s", node_item.NodeName().c_str(), src_node->GetName().c_str()); | |||
| RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] Start", | |||
| src_node->GetName().c_str()); | |||
| if (!subgraph_context_->Await(src_node)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Await node failed.", src_node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] End", | |||
| src_node->GetName().c_str()); | |||
| GELOGI("[%s] Done waiting node.", src_node->GetName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status ShapeInferenceEngine::PropagateOutputShapes(const NodeItem &node_item) { | |||
| void ShapeInferenceEngine::PropagateOutputShapes(InferenceState &entry, std::queue<InferenceState *> &queue) { | |||
| auto &node_item = entry.node_item; | |||
| // output shape will not be valid until compute is done. | |||
| bool shape_is_future = | |||
| node_item.shape_inference_type == DEPEND_SHAPE_RANGE || node_item.shape_inference_type == DEPEND_COMPUTE; | |||
| @@ -105,25 +171,88 @@ Status ShapeInferenceEngine::PropagateOutputShapes(const NodeItem &node_item) { | |||
| // propagate output to all sub-inputs | |||
| for (auto &dst_input_index_and_node : output_nodes) { | |||
| auto &dst_node_item = dst_input_index_and_node.second; | |||
| auto dst_node_state = subgraph_context_->GetOrCreateNodeState(dst_node_item); | |||
| GE_CHECK_NOTNULL(dst_node_state); | |||
| auto inference_state = GetOrCreateEntry(*dst_node_item); | |||
| GELOGI("[%s] Update dst node [%s], input index = %d", node_item.NodeName().c_str(), | |||
| dst_node_item->NodeName().c_str(), dst_input_index_and_node.first); | |||
| // in case type 3 and 4, shape will be valid after computing is done | |||
| // in case type 3/4, shape will be valid after computing is done | |||
| if (shape_is_future) { | |||
| ShapeFuture future(node_item.node, i, subgraph_context_); | |||
| dst_node_state->GetShapeInferenceState().UpdateInputShapeFuture(dst_input_index_and_node.first, | |||
| std::move(future)); | |||
| ShapeFuture future(node_item.node, i, &context_->cv_manager); | |||
| inference_state->UpdateInputShapeFuture(dst_input_index_and_node.first, std::move(future)); | |||
| } else { | |||
| dst_node_state->GetShapeInferenceState().UpdateInputShape(dst_input_index_and_node.first, ori_shape, shape); | |||
| inference_state->UpdateInputShape(dst_input_index_and_node.first, ori_shape, shape); | |||
| } | |||
| if (inference_state->IsInputShapesReady()) { | |||
| GELOGI("[%s] Node input shape is ready, add to queue.", inference_state->node_item.NodeName().c_str()); | |||
| queue.emplace(inference_state); | |||
| } | |||
| } | |||
| } | |||
| GELOGD("[%s] Propagating output shapes finished successfully.", node_item.NodeName().c_str()); | |||
| } | |||
| ShapeInferenceEngine::InferenceState *ShapeInferenceEngine::GetOrCreateEntry(const NodeItem &node_item) { | |||
| auto &node_state = inference_states_[node_item.node_id]; | |||
| if (node_state == nullptr) { | |||
| node_state.reset(new (std::nothrow) InferenceState(node_item)); | |||
| } | |||
| return node_state.get(); | |||
| } | |||
| ShapeInferenceEngine::InferenceState::InferenceState(const NodeItem &node_item) : node_item(node_item) { | |||
| this->num_pending_shapes = node_item.num_inputs; | |||
| } | |||
| void ShapeInferenceEngine::InferenceState::UpdateInputShape(uint32_t idx, const GeShape &ori_shape, | |||
| const GeShape &shape) { | |||
| if (node_item.const_input_shapes.count(idx) != 0) { | |||
| GELOGD("[%s] Trying to update constant shape, idx = %u. old shape = [%s], new shape = [%s]", | |||
| node_item.NodeName().c_str(), idx, node_item.op_desc->MutableInputDesc(idx)->GetShape().ToString().c_str(), | |||
| shape.ToString().c_str()); | |||
| } | |||
| GELOGD("[%s] Update input shape [%u] with Shape: [%s] and OriginalShape: [%s]", node_item.NodeName().c_str(), idx, | |||
| shape.ToString().c_str(), ori_shape.ToString().c_str()); | |||
| num_pending_shapes -= 1; | |||
| node_item.op_desc->MutableInputDesc(idx)->SetShape(shape); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); | |||
| } | |||
| void ShapeInferenceEngine::InferenceState::UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future) { | |||
| if (node_item.const_input_shapes.count(idx) != 0) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Trying to update constant shape, idx = %u", node_item.NodeName().c_str(), idx); | |||
| return; | |||
| } | |||
| GELOGD("[%s] Update input shape [%u] with ShapeFuture.", node_item.NodeName().c_str(), idx); | |||
| num_pending_shapes -= 1; | |||
| shape_futures.emplace_back(idx, std::move(future)); | |||
| } | |||
| Status ShapeInferenceEngine::InferenceState::AwaitShapeFutures(GraphExecutionContext *context) { | |||
| for (auto &p : shape_futures) { | |||
| auto idx = p.first; | |||
| auto &future = p.second; | |||
| GeShape shape; | |||
| GeShape ori_shape; | |||
| RECORD_SHAPE_INFERENCE_EVENT(context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] Start", idx); | |||
| GE_CHK_STATUS_RET(future.Get(ori_shape, shape), "[%s] Get shape failed. index = %u", node_item.NodeName().c_str(), | |||
| idx); | |||
| RECORD_SHAPE_INFERENCE_EVENT(context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] End", idx); | |||
| GELOGD("[%s] Update input shape [%u] with shape: [%s] and ori_shape: [%s]", node_item.NodeName().c_str(), idx, | |||
| shape.ToString().c_str(), ori_shape.ToString().c_str()); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetShape(std::move(shape)); | |||
| node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| ShapeInferenceEngine::ShapeFuture::ShapeFuture(NodePtr src_node, uint32_t src_index, NodeDoneManager *node_done_manager) | |||
| : src_node_(std::move(src_node)), src_index_(src_index), node_done_manager_(node_done_manager) {} | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| } // namespace ge | |||
| @@ -17,25 +17,75 @@ | |||
| #ifndef GE_HYBRID_EXECUTOR_INFERSHAPE_SHAPE_INFERENCE_ENGINE_H_ | |||
| #define GE_HYBRID_EXECUTOR_INFERSHAPE_SHAPE_INFERENCE_ENGINE_H_ | |||
| #include <memory> | |||
| #include <thread> | |||
| #include <unordered_map> | |||
| #include "common/thread_pool.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/subgraph_context.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class ShapeInferenceEngine { | |||
| public: | |||
| ShapeInferenceEngine(GraphExecutionContext *execution_context, SubgraphContext *subgraph_context); | |||
| ~ShapeInferenceEngine() = default; | |||
| explicit ShapeInferenceEngine(GraphExecutionContext *context); | |||
| Status InferShape(NodeState &node_state); | |||
| ~ShapeInferenceEngine() = default; | |||
| Status PropagateOutputShapes(const NodeItem &node_item); | |||
| Status Start(ThreadPool &pool); | |||
| private: | |||
| Status AwaitDependentNodes(NodeState &node_state); | |||
| class ShapeFuture { | |||
| public: | |||
| ShapeFuture(NodePtr src_node, uint32_t src_index, NodeDoneManager *node_done_manager); | |||
| ~ShapeFuture() = default; | |||
| Status Get(GeShape &ori_shape, GeShape &shape) { | |||
| GELOGI("Start to wait node: %s for getting shape", src_node_->GetName().c_str()); | |||
| if (!node_done_manager_->Await(src_node_)) { | |||
| GELOGE(INTERNAL_ERROR, "cancelled"); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->MutableShape(); | |||
| ori_shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->GetOriginShape(); | |||
| GELOGI("Get shape from %s:%u. shape = [%s]", src_node_->GetName().c_str(), src_index_, shape.ToString().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| private: | |||
| NodePtr src_node_; | |||
| uint32_t src_index_; | |||
| NodeDoneManager *node_done_manager_; | |||
| }; | |||
| struct InferenceState { | |||
| explicit InferenceState(const NodeItem &node_item); | |||
| inline bool IsInputShapesReady() const { return num_pending_shapes == 0; } | |||
| void UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape); | |||
| Status AwaitShapeFutures(GraphExecutionContext *context); | |||
| void UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future); | |||
| const NodeItem &node_item; | |||
| private: | |||
| std::vector<std::pair<uint32_t, ShapeFuture>> shape_futures; | |||
| int num_pending_shapes = 0; | |||
| }; | |||
| InferenceState *GetOrCreateEntry(const NodeItem &node_item); | |||
| Status InferShapeProcess(); | |||
| void InferenceDone(Status status); | |||
| Status InferShape(InferenceState &entry); | |||
| void PropagateOutputShapes(InferenceState &entry, std::queue<InferenceState *> &queue); | |||
| GraphExecutionContext *execution_context_; | |||
| SubgraphContext *subgraph_context_; | |||
| GraphExecutionContext *context_; | |||
| std::unordered_map<int64_t, std::unique_ptr<InferenceState>> inference_states_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -16,22 +16,172 @@ | |||
| #include "hybrid/executor/worker/task_compile_engine.h" | |||
| #include "init/gelib.h" | |||
| #include "framework/common/debug/log.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| Status TaskCompileEngine::Compile(NodeState &node_state, GraphExecutionContext *context) { | |||
| const auto &node_item = *node_state.GetNodeItem(); | |||
| RECORD_COMPILE_EVENT(context, node_item.NodeName().c_str(), "Start"); | |||
| GE_CHK_RT_RET(rtCtxSetCurrent(context->rt_gen_context)); | |||
| shared_ptr<NodeTask> kernel_task; | |||
| auto ret = node_item.node_executor->CompileTask(*context->model, node_item.node, kernel_task); | |||
| RECORD_COMPILE_EVENT(context, node_state.GetName().c_str(), "End"); | |||
| namespace { | |||
| uint32_t kDefaultWorkerCnt = 4; | |||
| uint32_t kDefaultDeviceId = 0; | |||
| } // namespace | |||
| TaskCompileEngine::TaskCompileEngine(GraphExecutionContext *context) : context_(context), pool_(kDefaultWorkerCnt) {} | |||
| TaskCompileEngine::~TaskCompileEngine() { | |||
| if (rt_context_ != nullptr) { | |||
| GELOGD("To destroy compile context: %p.", rt_context_); | |||
| GE_CHK_RT(rtCtxDestroy(rt_context_)); | |||
| } | |||
| } | |||
| Status TaskCompileEngine::Init() { | |||
| GELOGD("Start to init CompileEngine"); | |||
| rtContext_t current_ctx = nullptr; | |||
| GE_CHK_RT(rtCtxGetCurrent(¤t_ctx)); | |||
| GE_CHK_RT_RET(rtCtxCreate(&rt_context_, RT_CTX_GEN_MODE, kDefaultDeviceId)); | |||
| GELOGD("Context created for compiling. ctx = %p", rt_context_); | |||
| GE_CHK_RT_RET(rtCtxSetCurrent(current_ctx)); | |||
| return SUCCESS; | |||
| } | |||
| void TaskCompileEngine::Reset() { | |||
| complete_queue_.Push(nullptr); // ensure iteration can stop | |||
| unique_ptr<ResultQueueEntry> entry; | |||
| while (true) { | |||
| complete_queue_.Pop(entry); | |||
| if (entry == nullptr) { | |||
| break; | |||
| } | |||
| if (entry->future != nullptr) { | |||
| entry->future->wait(); | |||
| } | |||
| } | |||
| complete_queue_.Clear(); | |||
| } | |||
| Status TaskCompileEngine::Start(ThreadPool &pool) { | |||
| pool.commit([&]() { (void)this->CompileProcess(); }); | |||
| worker_future_ = pool_.commit([&]() -> Status { return this->DistributeCompiledTasks(); }); | |||
| if (!worker_future_.valid()) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to start worker thread"); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status TaskCompileEngine::CompileProcess() { | |||
| auto &compile_queue = context_->compile_queue; | |||
| while (true) { | |||
| NodeStatePtr node_state; | |||
| // Stop() will not be invoked, Pop won't failed | |||
| (void)compile_queue.Pop(node_state); | |||
| // EOF | |||
| if (node_state == nullptr) { | |||
| GELOGD("Got EOF"); | |||
| complete_queue_.Push(unique_ptr<ResultQueueEntry>()); | |||
| break; | |||
| } | |||
| auto entry = unique_ptr<ResultQueueEntry>(new (std::nothrow) ResultQueueEntry()); | |||
| GE_CHECK_NOTNULL(entry); | |||
| entry->node_state = node_state; | |||
| auto node_item = *node_state->node_item; | |||
| if (node_item.kernel_task != nullptr) { | |||
| GELOGD("use precompiled task. node name = %s", node_item.NodeName().c_str()); | |||
| node_state->kernel_task = node_item.kernel_task; | |||
| complete_queue_.Push(std::move(entry)); | |||
| continue; | |||
| } | |||
| auto ret = CompileAsync(*node_state->node_item, *entry); | |||
| if (ret == SUCCESS) { | |||
| complete_queue_.Push(std::move(entry)); | |||
| continue; | |||
| } | |||
| // On Error | |||
| worker_future_.wait(); | |||
| Reset(); | |||
| return CompileDone(ret); | |||
| } | |||
| Status ret = worker_future_.get(); | |||
| Reset(); | |||
| return CompileDone(ret); | |||
| } | |||
| Status TaskCompileEngine::CompileDone(Status status) { | |||
| if (status != SUCCESS) { | |||
| GELOGE(status, "Error occurred while compiling node."); | |||
| context_->OnError(status); | |||
| } else { | |||
| context_->execution_queue.Push(nullptr); | |||
| } | |||
| GELOGI("CompileEngine worker END. ret = %u", status); | |||
| return status; | |||
| } | |||
| Status TaskCompileEngine::DoCompile(const NodeItem &node_item, NodeState &node_state) { | |||
| RECORD_COMPILE_EVENT(context_, node_state.GetName().c_str(), "Start"); | |||
| GE_CHK_RT_RET(rtCtxSetCurrent(rt_context_)); | |||
| auto ret = node_item.node_executor->CompileTask(*context_->model, node_item.node, node_state.kernel_task); | |||
| RECORD_COMPILE_EVENT(context_, node_state.GetName().c_str(), "End"); | |||
| GE_CHK_STATUS_RET(ret, "Failed to create task for node: %s", node_item.NodeName().c_str()); | |||
| node_state.SetKernelTask(kernel_task); | |||
| GELOGI("Compiling node %s successfully", node_state.GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status TaskCompileEngine::CompileAsync(const NodeItem &node_item, ResultQueueEntry &entry) { | |||
| auto node_state = entry.node_state; | |||
| auto f = pool_.commit([this, node_item, node_state]() -> Status { return DoCompile(node_item, *node_state); }); | |||
| if (!f.valid()) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to commit compile task"); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| entry.future = unique_ptr<std::future<Status>>(new (std::nothrow) std::future<Status>(std::move(f))); | |||
| GE_CHECK_NOTNULL(entry.future); | |||
| return SUCCESS; | |||
| } | |||
| Status TaskCompileEngine::DistributeCompiledTasks() { | |||
| GELOGD("DistributeCompiledTasks start."); | |||
| auto &execute_queue = context_->execution_queue; | |||
| unique_ptr<ResultQueueEntry> entry; | |||
| bool ret = SUCCESS; | |||
| while (true) { | |||
| if (!complete_queue_.Pop(entry)) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to pop item from queue"); | |||
| ret = INTERNAL_ERROR; | |||
| break; | |||
| } | |||
| // EOF | |||
| if (entry == nullptr) { | |||
| break; | |||
| } | |||
| // if has compile future | |||
| if (entry->future != nullptr) { | |||
| ret = entry->future->get(); | |||
| if (ret != SUCCESS) { | |||
| break; | |||
| } | |||
| } | |||
| execute_queue.Push(entry->node_state); | |||
| } | |||
| GELOGD("DistributeCompiledTasks out. ret = %u.", ret); | |||
| return ret; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| } // namespace ge | |||
| @@ -17,13 +17,44 @@ | |||
| #ifndef GE_HYBRID_EXECUTOR_COMPILE_TASK_COMPILE_ENGINE_H_ | |||
| #define GE_HYBRID_EXECUTOR_COMPILE_TASK_COMPILE_ENGINE_H_ | |||
| #include <memory> | |||
| #include <thread> | |||
| #include "common/thread_pool.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class TaskCompileEngine { | |||
| public: | |||
| static Status Compile(NodeState &node_state, GraphExecutionContext *context); | |||
| explicit TaskCompileEngine(GraphExecutionContext *context); | |||
| ~TaskCompileEngine(); | |||
| Status Init(); | |||
| Status Start(ThreadPool &pool); | |||
| private: | |||
| struct ResultQueueEntry { | |||
| NodeStatePtr node_state; | |||
| std::unique_ptr<std::future<Status>> future; | |||
| }; | |||
| Status CompileProcess(); | |||
| Status CompileDone(Status status); | |||
| private: | |||
| Status DoCompile(const NodeItem &node_item, NodeState &node_state); | |||
| Status CompileAsync(const NodeItem &node_item, ResultQueueEntry &entry); | |||
| Status DistributeCompiledTasks(); | |||
| void Reset(); | |||
| rtContext_t rt_context_ = nullptr; | |||
| GraphExecutionContext *context_; | |||
| BlockingQueue<unique_ptr<ResultQueueEntry>> complete_queue_; | |||
| ThreadPool pool_; | |||
| std::future<Status> worker_future_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -18,7 +18,6 @@ | |||
| #include "hybrid_davinci_model.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| #include "hybrid/executor/hybrid_model_async_executor.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| @@ -26,19 +25,14 @@ class HybridDavinciModel::Impl { | |||
| public: | |||
| explicit Impl(GeRootModelPtr ge_model) : model_(std::move(ge_model)), executor_(&model_) {} | |||
| ~Impl() { NodeExecutorManager::GetInstance().FinalizeExecutors(); } | |||
| ~Impl() = default; | |||
| Status Init() { | |||
| GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().EnsureInitialized(), "Failed to initialize executors"); | |||
| GE_CHK_STATUS_RET(model_.Init(), "Failed to init model.") | |||
| GE_CHK_STATUS_RET(executor_.Init(), "Failed to init model executor.") | |||
| return SUCCESS; | |||
| } | |||
| Status Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs) { | |||
| return executor_.Execute(inputs, outputs); | |||
| } | |||
| Status ModelRunStart() { return executor_.Start(listener_); } | |||
| Status ModelRunStop() { return executor_.Stop(); } | |||
| @@ -82,11 +76,6 @@ Status HybridDavinciModel::Init() { | |||
| return impl_->Init(); | |||
| } | |||
| Status HybridDavinciModel::Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs) { | |||
| GE_CHECK_NOTNULL(impl_); | |||
| return impl_->Execute(inputs, outputs); | |||
| } | |||
| Status HybridDavinciModel::ModelRunStart() { | |||
| GE_CHECK_NOTNULL(impl_); | |||
| return impl_->ModelRunStart(); | |||
| @@ -37,8 +37,6 @@ class HybridDavinciModel { | |||
| Status Init(); | |||
| Status Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs); | |||
| Status ModelRunStart(); | |||
| Status ModelRunStop(); | |||
| @@ -26,8 +26,6 @@ std::unique_ptr<HybridDavinciModel> HybridDavinciModel::Create(const GeRootModel | |||
| Status HybridDavinciModel::Init() { return UNSUPPORTED; } | |||
| Status HybridDavinciModel::Execute(const vector<GeTensor> &inputs, vector<GeTensor> &outputs) { return UNSUPPORTED; } | |||
| Status HybridDavinciModel::ModelRunStart() { return UNSUPPORTED; } | |||
| Status HybridDavinciModel::ModelRunStop() { return UNSUPPORTED; } | |||
| @@ -1,62 +0,0 @@ | |||
| /** | |||
| * 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 "framework/common/util.h" | |||
| #include "graph_item.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr int kInvalidIndex = -1; | |||
| } // namespace | |||
| GraphItem::~GraphItem() { GELOGD("[%s] GraphItem destroyed.", name_.c_str()); } | |||
| const vector<NodeItem *> &hybrid::GraphItem::GetAllNodes() const { return node_items_; } | |||
| const vector<const NodeItem *> &GraphItem::GetInputNodes() const { return input_nodes_; } | |||
| Status GraphItem::GetOutputDescList(vector<ConstGeTensorDescPtr> &output_desc_list) const { | |||
| if (is_dynamic_) { | |||
| for (auto &node_and_idx : output_edges_) { | |||
| const auto &tensor_desc = node_and_idx.first->op_desc->MutableOutputDesc(node_and_idx.second); | |||
| GE_CHECK_NOTNULL(tensor_desc); | |||
| output_desc_list.emplace_back(tensor_desc); | |||
| } | |||
| } else { | |||
| auto all_output_desc = output_node_->op_desc->GetAllOutputsDescPtr(); | |||
| for (auto &tensor_desc : output_node_->op_desc->GetAllOutputsDescPtr()) { | |||
| output_desc_list.emplace_back(tensor_desc); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| bool GraphItem::IsDynamic() const { return is_dynamic_; } | |||
| const vector<int> &GraphItem::GetInputIndexMapping() const { return input_index_mapping_; } | |||
| int GraphItem::GetParentOutputIndex(size_t index) const { | |||
| if (index >= output_index_mapping_.size()) { | |||
| return kInvalidIndex; | |||
| } | |||
| return output_index_mapping_[index]; | |||
| } | |||
| const NodeItem *GraphItem::GetOutputNode() const { return output_node_; } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,64 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ | |||
| #define GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ | |||
| #include "external/ge/ge_api_error_codes.h" | |||
| #include "hybrid/model/node_item.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class GraphItem { | |||
| public: | |||
| GraphItem() = default; | |||
| ~GraphItem(); | |||
| const vector<NodeItem *> &GetAllNodes() const; | |||
| const vector<const NodeItem *> &GetInputNodes() const; | |||
| Status GetOutputDescList(std::vector<ConstGeTensorDescPtr> &output_desc_list) const; | |||
| int TotalInputs() const { return total_inputs_; } | |||
| int TotalOutputs() const { return total_outputs_; } | |||
| const std::string &GetName() const { return name_; } | |||
| void SetName(const string &name) { name_ = name; } | |||
| const NodeItem *GetOutputNode() const; | |||
| bool IsDynamic() const; | |||
| int GetParentOutputIndex(size_t index) const; | |||
| const vector<int> &GetInputIndexMapping() const; | |||
| private: | |||
| friend class HybridModelBuilder; | |||
| std::string name_; | |||
| std::vector<NodeItem *> node_items_; | |||
| std::vector<const NodeItem *> input_nodes_; | |||
| const NodeItem *output_node_ = nullptr; | |||
| // <src_node, out_index> | |||
| std::vector<std::pair<const NodeItem *, int>> output_edges_; | |||
| int total_inputs_ = 0; | |||
| int total_outputs_ = 0; | |||
| bool is_dynamic_ = true; | |||
| std::vector<int> input_index_mapping_; | |||
| std::vector<int> output_index_mapping_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ | |||
| @@ -29,8 +29,6 @@ namespace ge { | |||
| namespace hybrid { | |||
| HybridModel::HybridModel(GeRootModelPtr ge_model) : ge_root_model_(std::move(ge_model)) {} | |||
| HybridModel::~HybridModel() { GELOGD("[%s] HybridModel destroyed.", model_name_.c_str()); } | |||
| Status HybridModel::Init() { | |||
| GELOGD("Start to init hybrid model."); | |||
| GE_CHK_STATUS_RET(HybridModelBuilder(*this).Build(), "Failed to build hybrid model."); | |||
| @@ -38,6 +36,22 @@ Status HybridModel::Init() { | |||
| return SUCCESS; | |||
| } | |||
| void HybridModel::Print() const { | |||
| for (const auto &node : node_items_) { | |||
| GELOGD("%s", node->DebugString().c_str()); | |||
| } | |||
| } | |||
| TensorValue *HybridModel::GetWeight(const NodeItem *const_node) const { | |||
| auto it = weights_.find(const_node->node_id); | |||
| if (it == weights_.end() || it->second == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Failed to get weight", const_node->NodeName().c_str()); | |||
| return nullptr; | |||
| } | |||
| return it->second.get(); | |||
| } | |||
| TensorValue *HybridModel::GetVariable(const string &name) const { | |||
| auto it = variable_tensors_.find(name); | |||
| if (it == variable_tensors_.end()) { | |||
| @@ -69,26 +83,26 @@ const std::vector<domi::TaskDef> *HybridModel::GetTaskDefs(const NodePtr &node) | |||
| } | |||
| NodeItem *HybridModel::MutableNodeItem(const NodePtr &node) { | |||
| auto it = node_items_.find(node); | |||
| if (it == node_items_.end()) { | |||
| auto node_id = node->GetOpDesc()->GetId(); | |||
| if (node_id < 0 || static_cast<size_t>(node_id) > node_items_.size()) { | |||
| GELOGE(INTERNAL_ERROR, "index out of range. node_id = %ld, num_nodes = %zu", node_id, node_items_.size()); | |||
| return nullptr; | |||
| } | |||
| return it->second.get(); | |||
| return node_items_[node_id].get(); | |||
| } | |||
| const NodeItem *HybridModel::GetNodeItem(const NodePtr &node) const { | |||
| auto it = node_items_.find(node); | |||
| if (it == node_items_.end()) { | |||
| auto node_id = node->GetOpDesc()->GetId(); | |||
| if (node_id < 0 || static_cast<size_t>(node_id) > node_items_.size()) { | |||
| GELOGE(INTERNAL_ERROR, "Index out of range. node_id = %ld, num_nodes = %zu.", node_id, node_items_.size()); | |||
| return nullptr; | |||
| } | |||
| return it->second.get(); | |||
| return node_items_[node_id].get(); | |||
| } | |||
| GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const { | |||
| auto it = known_shape_sub_models_.find(node); | |||
| if (it == known_shape_sub_models_.end()) { | |||
| auto it = known_shape_sub_graphs_.find(node); | |||
| if (it == known_shape_sub_graphs_.end()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Failed to get GeModel for subgraph node.", node->GetName().c_str()); | |||
| return nullptr; | |||
| } | |||
| @@ -96,27 +110,8 @@ GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const { | |||
| return it->second; | |||
| } | |||
| const GraphItem *HybridModel::GetRootGraphItem() const { return root_graph_item_.get(); } | |||
| const GraphItem *HybridModel::GetSubgraphItem(const std::string &graph_name) const { | |||
| GELOGD("To find subgraph item by name = %s", graph_name.c_str()); | |||
| auto it = subgraph_items_.find(graph_name); | |||
| if (it == subgraph_items_.end()) { | |||
| GELOGD("Subgraph item not found by node = %s", graph_name.c_str()); | |||
| return nullptr; | |||
| } | |||
| return it->second.get(); | |||
| } | |||
| const GraphItem *HybridModel::GetSubgraphItem(const ComputeGraphPtr &subgraph) const { | |||
| if (subgraph == nullptr) { | |||
| GELOGE(PARAM_INVALID, "subgraph is nullptr"); | |||
| return nullptr; | |||
| } | |||
| const vector<int> &HybridModel::GetNetOutputInputOffsets() const { return net_output_input_offsets_; } | |||
| auto subgraph_name = subgraph->GetName(); | |||
| return GetSubgraphItem(subgraph_name); | |||
| } | |||
| void HybridModel::SetDeviceId(uint32_t device_id) { device_id_ = device_id; } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -26,23 +26,39 @@ | |||
| #include "graph/node.h" | |||
| #include "hybrid/common/tensor_value.h" | |||
| #include "hybrid/model/node_item.h" | |||
| #include "hybrid/model/graph_item.h" | |||
| #include "model/ge_root_model.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class HybridModelAsyncExecutor; | |||
| class HybridModel { | |||
| public: | |||
| explicit HybridModel(GeRootModelPtr ge_model); | |||
| ~HybridModel(); | |||
| ~HybridModel() = default; | |||
| Status Init(); | |||
| const std::vector<NodeItem *> &RootNodes() const { return root_nodes_; } | |||
| const NodeItem *GetNodeItem(const NodePtr &node) const; | |||
| size_t NumNodes() const { return node_items_.size(); } | |||
| uint64_t GetSessionId() const { return root_runtime_param_.session_id; } | |||
| int TotalInputs() const { return total_inputs_; } | |||
| const map<uint32_t, NodeItem *> &GetInputNodes() const { return input_nodes_; } | |||
| const std::map<uint32_t, std::vector<int>> &GetInputOffsets() const { return input_offsets_; } | |||
| const vector<int> &GetNetOutputInputOffsets() const; | |||
| const std::vector<int> &GetOutputOffsets() const { return output_offsets_; } | |||
| const std::vector<NodeItem *> &GetConstNodes() const { return const_nodes_; } | |||
| GeModelPtr GetGeModel(const NodePtr &node) const; | |||
| NodeItem *MutableNodeItem(const NodePtr &node); | |||
| @@ -51,40 +67,46 @@ class HybridModel { | |||
| const uint8_t *GetVarMemBase() const { return var_mem_base_; } | |||
| void SetDeviceId(uint32_t device_id) { device_id_ = device_id; } | |||
| void SetDeviceId(uint32_t device_id); | |||
| void SetModelId(uint32_t model_id) { model_id_ = model_id; } | |||
| uint32_t GetModelId() const { return model_id_; } | |||
| TensorValue *GetWeight(const NodeItem *const_node) const; | |||
| TensorValue *GetVariable(const string &name) const; | |||
| NodePtr GetVariableNode(const string &name) const; | |||
| const std::vector<domi::TaskDef> *GetTaskDefs(const NodePtr &node) const; | |||
| const GraphItem *GetRootGraphItem() const; | |||
| int TotalOutputs() const { return total_outputs_; } | |||
| const GraphItem *GetSubgraphItem(const std::string &graph_name) const; | |||
| const GraphItem *GetSubgraphItem(const ComputeGraphPtr &subgraph) const; | |||
| GeRootModelPtr GetGeRootModel() const { return ge_root_model_; } | |||
| void Print() const; | |||
| private: | |||
| friend class HybridModelBuilder; | |||
| friend class HybridModelAsyncExecutor; | |||
| std::string model_name_; | |||
| GeRootModelPtr ge_root_model_; | |||
| std::vector<NodeItem *> root_nodes_; | |||
| std::map<uint32_t, NodeItem *> input_nodes_; | |||
| std::map<uint32_t, std::vector<int>> input_offsets_; | |||
| std::vector<int> output_offsets_; | |||
| std::vector<int> net_output_input_offsets_; | |||
| NodeItem *net_output_node_ = nullptr; | |||
| std::vector<std::unique_ptr<NodeItem>> node_items_; | |||
| std::vector<NodeItem *> const_nodes_; | |||
| std::map<std::string, NodePtr> constant_op_nodes_; | |||
| std::map<std::string, NodePtr> variable_nodes_; | |||
| std::map<std::string, std::unique_ptr<TensorValue>> variable_tensors_; | |||
| std::map<int, std::unique_ptr<TensorValue>> weights_; | |||
| std::map<NodePtr, std::vector<domi::TaskDef>> task_defs_; | |||
| std::map<NodePtr, GeModelPtr> known_shape_sub_models_; | |||
| std::unique_ptr<GraphItem> root_graph_item_; | |||
| std::map<std::string, std::unique_ptr<GraphItem>> subgraph_items_; | |||
| std::map<NodePtr, std::unique_ptr<NodeItem>> node_items_; | |||
| std::map<NodePtr, GeModelPtr> known_shape_sub_graphs_; | |||
| int total_inputs_ = 0; | |||
| int total_outputs_ = 0; | |||
| // runtime fields | |||
| uint32_t device_id_ = 0; | |||
| @@ -23,6 +23,7 @@ | |||
| #include "graph/manager/trans_var_data_utils.h" | |||
| #include "graph/utils/graph_utils.h" | |||
| #include "graph/utils/type_utils.h" | |||
| #include "framework/common/debug/log.h" | |||
| #include "hybrid/common/npu_memory_allocator.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| @@ -31,7 +32,6 @@ namespace hybrid { | |||
| namespace { | |||
| const uint32_t kSubgraphIndex = 0U; | |||
| const uint32_t kVarOutputIndex = 0U; | |||
| const uint32_t kAlignment = 32; | |||
| const int kBytes = 8; | |||
| int64_t CalcVarSizeInBytes(const GeTensorDesc &desc) { | |||
| @@ -46,9 +46,6 @@ int64_t CalcVarSizeInBytes(const GeTensorDesc &desc) { | |||
| for (size_t dim_index = 0; dim_index < dim_num; ++dim_index) { | |||
| var_size *= shape.GetDim(dim_index); | |||
| } | |||
| // padding up to multiple of kAlignment, and add extra kAlignment | |||
| var_size = (var_size + kAlignment * 2 - 1) / kAlignment * kAlignment; | |||
| return var_size; | |||
| } | |||
| } // namespace | |||
| @@ -59,19 +56,20 @@ HybridModelBuilder::HybridModelBuilder(HybridModel &hybrid_model) | |||
| Status HybridModelBuilder::Build() { | |||
| GE_CHK_STATUS_RET(ValidateParams(), "Failed to validate GeRootModel"); | |||
| hybrid_model_.model_name_ = ge_root_model_->GetRootGraph()->GetName(); | |||
| graph_name_ = ge_root_model_->GetRootGraph()->GetName(); | |||
| GELOGI("[%s] Start to build hybrid model.", GetGraphName()); | |||
| GE_CHK_STATUS_RET(InitRuntimeParams(), "[%s] Failed to InitRuntimeParams", GetGraphName()); | |||
| GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().EnsureInitialized(), "Failed to initialize executors"); | |||
| GE_CHK_STATUS_RET(IndexSpecialNodes(), "[%s] Failed to index nodes", GetGraphName()); | |||
| GE_CHK_STATUS_RET(IndexTaskDefs(), "[%s] Failed to index task defs", GetGraphName()); | |||
| GE_CHK_STATUS_RET(LoadGraph(), "[%s] Failed to load graph", GetGraphName()); | |||
| GE_CHK_STATUS_RET(AssignUninitializedConstantOps(), "[%s] Failed to assign uninitialized constants", GetGraphName()); | |||
| GE_CHK_STATUS_RET(TransAllVarData(), "[%s] Failed to trans all var data", GetGraphName()); | |||
| GE_CHK_STATUS_RET(CopyVarData(), "[%s] Failed to copy var data", GetGraphName()); | |||
| GE_CHK_STATUS_RET(InitModelMem(), "[%s] Failed to init memory", GetGraphName()); | |||
| GE_CHK_STATUS_RET(InitWeights(), "[%s] Failed to init weights", GetGraphName()); | |||
| GE_CHK_STATUS_RET(InitConstantOps(), "[%s] Failed to init constant op", GetGraphName()); | |||
| GE_CHK_STATUS_RET(InitVariableTensors(), "[%s] Failed to init variables", GetGraphName()); | |||
| GE_CHK_STATUS_RET(ResolveRootNodes(), "[%s] Failed to resolve root nodes", GetGraphName()); | |||
| GE_CHK_STATUS_RET(LoadTasks(), "[%s] Failed to load tasks", GetGraphName()); | |||
| GELOGI("[%s] Done building hybrid model successfully.", GetGraphName()); | |||
| return SUCCESS; | |||
| @@ -83,17 +81,45 @@ Status HybridModelBuilder::ValidateParams() { | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::BuildNodeItem(const NodePtr &node, NodeItem &node_item) { | |||
| Status HybridModelBuilder::ResolveRootNodes() { | |||
| for (auto &node : hybrid_model_.node_items_) { | |||
| if (node->node->GetInDataNodes().empty()) { | |||
| hybrid_model_.root_nodes_.emplace_back(node.get()); | |||
| GELOGI("[%s] Root node added. node name = %s", GetGraphName(), node->NodeName().c_str()); | |||
| } | |||
| } | |||
| if (hybrid_model_.root_nodes_.empty()) { | |||
| GELOGE(PARAM_INVALID, "[%s] Root nodes is empty.", GetGraphName()); | |||
| return PARAM_INVALID; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::BuildNoteItem(const NodePtr &node, NodeItem &node_item) { | |||
| GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node, node_item.is_dynamic), | |||
| "[%s] Failed to get shape status.", node->GetName().c_str()); | |||
| auto op_desc = node->GetOpDesc(); | |||
| vector<string> dependencies = node->GetOpDesc()->GetOpInferDepends(); | |||
| GE_CHK_STATUS_RET(ParseDependentInputNodes(node_item, dependencies), "[%s] Failed to parse node dependencies.", | |||
| node_item.NodeName().c_str()); | |||
| auto it = node_ref_inputs_.find(node); | |||
| if (it != node_ref_inputs_.end()) { | |||
| for (auto &idx_and_node : it->second) { | |||
| // var and constant only have one output | |||
| node_item.const_input_shapes[idx_and_node.first] = | |||
| idx_and_node.second->GetOpDesc()->MutableOutputDesc(kVarOutputIndex); | |||
| } | |||
| } | |||
| node_item.outputs.resize(node_item.num_outputs); | |||
| for (int i = 0; i < node_item.num_outputs; ++i) { | |||
| auto out_data_anchor = node->GetOutDataAnchor(i); | |||
| if (out_data_anchor == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "out anchor[%d] of node %s is nullptr", i, node->GetName().c_str()); | |||
| GELOGE(INTERNAL_ERROR, "out anchor[%zu] of node %s is nullptr", i, node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| @@ -111,46 +137,27 @@ Status HybridModelBuilder::BuildNodeItem(const NodePtr &node, NodeItem &node_ite | |||
| } | |||
| } | |||
| GE_CHK_STATUS_RET_NOLOG(ResolveRefIo(node_item)); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::ResolveRefIo(NodeItem &node_item) { | |||
| bool is_ref = false; | |||
| auto &op_desc = *node_item.op_desc; | |||
| (void)AttrUtils::GetBool(op_desc, ATTR_NAME_REFERENCE, is_ref); | |||
| if (!is_ref) { | |||
| return SUCCESS; | |||
| } | |||
| auto inputs = op_desc.GetAllInputName(); | |||
| auto outputs = op_desc.GetAllOutputName(); | |||
| for (auto &output : outputs) { | |||
| for (auto &input : inputs) { | |||
| if (input.first == output.first) { | |||
| auto input_idx = static_cast<int>(input.second); | |||
| auto output_idx = static_cast<int>(output.second); | |||
| node_item.reuse_inputs[output_idx] = input_idx; | |||
| GELOGD("[%s] Output[%d] reuse input[%d]", node_item.NodeName().c_str(), output_idx, input_idx); | |||
| } | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::GetOrCreateNodeItem(const NodePtr &node, NodeItem **node_item) { | |||
| auto &node_items = hybrid_model_.node_items_; | |||
| auto it = node_items.find(node); | |||
| if (it != node_items.end()) { | |||
| *node_item = it->second.get(); | |||
| auto node_id = node->GetOpDesc()->GetId(); | |||
| if (node_id < 0 || static_cast<size_t>(node_id) > node_items.size()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Index out of range. node_id = %ld, num_nodes = %zu", node->GetName().c_str(), node_id, | |||
| node_items.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| auto &node_ptr = node_items[node_id]; | |||
| if (node_ptr != nullptr) { | |||
| *node_item = node_ptr.get(); | |||
| return SUCCESS; | |||
| } | |||
| auto new_node = std::unique_ptr<NodeItem>(new (std::nothrow) NodeItem(node)); | |||
| GE_CHECK_NOTNULL(new_node); | |||
| GE_CHECK_NOTNULL(new_node->op_desc); | |||
| GE_CHK_STATUS_RET(new_node->Init(), "Failed to init NodeItem [%s] .", node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET_NOLOG(NodeExecutorManager::GetInstance().GetExecutor(*node, &new_node->node_executor)); | |||
| // we do not need L2 Buffer | |||
| @@ -162,58 +169,18 @@ Status HybridModelBuilder::GetOrCreateNodeItem(const NodePtr &node, NodeItem **n | |||
| int32_t unknown_shape_type_val = 0; | |||
| (void)AttrUtils::GetInt(new_node->op_desc, ::ge::ATTR_NAME_UNKNOWN_SHAPE_TYPE, unknown_shape_type_val); | |||
| new_node->shape_inference_type = static_cast<UnknowShapeOpType>(unknown_shape_type_val); | |||
| GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node, new_node->is_dynamic), | |||
| "[%s] Failed to get shape status.", node->GetName().c_str()); | |||
| if (new_node->is_dynamic && (new_node->IsControlOp() || new_node->NodeType() == PARTITIONEDCALL)) { | |||
| new_node->shape_inference_type = DEPEND_COMPUTE; | |||
| if (new_node->shape_inference_type == DEPEND_SHAPE_RANGE || new_node->shape_inference_type == DEPEND_COMPUTE) { | |||
| new_node->has_observer = true; | |||
| } | |||
| new_node->node_id = node_index; | |||
| new_node->op_desc->SetId(node_index); | |||
| node_index += 1; | |||
| *node_item = new_node.get(); | |||
| node_items[node] = std::move(new_node); | |||
| node_items[node_id] = std::move(new_node); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::ParseDependentInputNodes(NodeItem &node_item, const std::vector<string> &dependencies) { | |||
| std::set<NodePtr> dependent_input_nodes; | |||
| auto &ge_node = node_item.node; | |||
| // The input tensors become valid after computation is done for parent nodes of type DEPEND_COMPUTE. | |||
| // Wait for these parent nodes before execution. | |||
| for (const auto &in_anchor : ge_node->GetAllInDataAnchors()) { | |||
| const auto &peer_anchor = in_anchor->GetPeerOutAnchor(); | |||
| if (peer_anchor == nullptr) { | |||
| GELOGD("[%s] Input[%d] do not have peer anchor", node_item.NodeName().c_str(), in_anchor->GetIdx()); | |||
| continue; | |||
| } | |||
| auto src_node = peer_anchor->GetOwnerNode(); | |||
| GE_CHECK_NOTNULL(src_node); | |||
| auto src_node_item = MutableNodeItem(src_node); | |||
| GE_CHECK_NOTNULL(src_node_item); | |||
| if (src_node_item->shape_inference_type == DEPEND_COMPUTE) { | |||
| GELOGD("[%s] Add input data dependent node [%s] due to inference type = DEPEND_COMPUTE", | |||
| node_item.NodeName().c_str(), src_node_item->NodeName().c_str()); | |||
| src_node_item->has_observer = true; | |||
| node_item.dependents_for_execution.emplace_back(src_node); | |||
| } | |||
| if (src_node_item->shape_inference_type == DEPEND_SHAPE_RANGE) { | |||
| GELOGD("[%s] Add input shape dependent node [%s] due to inference type = DEPEND_SHAPE_RANGE", | |||
| node_item.NodeName().c_str(), src_node_item->NodeName().c_str()); | |||
| src_node_item->has_observer = true; | |||
| dependent_input_nodes.emplace(src_node); | |||
| } | |||
| } | |||
| for (const auto &input_name : dependencies) { | |||
| int input_index = node_item.op_desc->GetInputIndexByName(input_name); | |||
| if (input_index < 0) { | |||
| @@ -238,7 +205,7 @@ Status HybridModelBuilder::ParseDependentInputNodes(NodeItem &node_item, const s | |||
| } | |||
| for (const auto &dep_node : dependent_input_nodes) { | |||
| node_item.dependents_for_shape_inference.emplace_back(dep_node); | |||
| node_item.dependent_node_list.emplace_back(dep_node); | |||
| } | |||
| return SUCCESS; | |||
| @@ -295,14 +262,9 @@ Status HybridModelBuilder::DoLinkDataAnchors(OutDataAnchorPtr &out_data_anchor, | |||
| Status HybridModelBuilder::MergeInputNodes(ComputeGraph &graph) { | |||
| const auto &wrapped_node = graph.GetParentNode(); | |||
| std::set<NodePtr> root_nodes; | |||
| for (const auto &node : graph.GetDirectNode()) { | |||
| GE_CHECK_NOTNULL(node); | |||
| if (node->GetType() != DATA_TYPE) { | |||
| if (node->GetInDataNodes().empty()) { | |||
| root_nodes.emplace(node); | |||
| } | |||
| continue; | |||
| } | |||
| @@ -329,28 +291,12 @@ Status HybridModelBuilder::MergeInputNodes(ComputeGraph &graph) { | |||
| for (auto &out_data_anchor : node->GetAllOutDataAnchors()) { | |||
| GE_CHECK_NOTNULL(out_data_anchor); | |||
| for (auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) { | |||
| auto dst_node = peer_in_data_anchor->GetOwnerNode(); | |||
| root_nodes.emplace(dst_node); | |||
| GE_CHK_STATUS_RET_NOLOG(DoUnlinkDataAnchors(out_data_anchor, peer_in_data_anchor)); | |||
| GE_CHK_STATUS_RET_NOLOG(DoLinkDataAnchors(src_out_anchor, peer_in_data_anchor)); | |||
| } | |||
| } | |||
| } | |||
| // transfer in control edges to all root nodes | |||
| for (auto &root_node : root_nodes) { | |||
| auto in_nodes = root_node->GetInAllNodes(); | |||
| std::set<NodePtr> in_node_set(in_nodes.begin(), in_nodes.end()); | |||
| for (auto &in_control_node : wrapped_node->GetInControlNodes()) { | |||
| if (in_node_set.count(in_control_node) == 0) { | |||
| GELOGD("[%s] Restore control edge to [%s]", in_control_node->GetName().c_str(), root_node->GetName().c_str()); | |||
| GE_CHECK_NOTNULL(in_control_node->GetOutControlAnchor()); | |||
| (void)in_control_node->GetOutControlAnchor()->LinkTo(root_node->GetInControlAnchor()); | |||
| } | |||
| } | |||
| } | |||
| wrapped_node->GetInControlAnchor()->UnlinkAll(); | |||
| return SUCCESS; | |||
| } | |||
| @@ -361,11 +307,6 @@ Status HybridModelBuilder::MergeNetOutputNode(ComputeGraph &graph) { | |||
| const auto &net_output_desc = net_output_node->GetOpDesc(); | |||
| GE_CHECK_NOTNULL(net_output_desc); | |||
| auto all_in_nodes = net_output_node->GetInAllNodes(); | |||
| auto all_out_nodes = parent_node->GetOutAllNodes(); | |||
| net_output_node->GetInControlAnchor()->UnlinkAll(); | |||
| parent_node->GetOutControlAnchor()->UnlinkAll(); | |||
| for (const auto &in_data_anchor : net_output_node->GetAllInDataAnchors()) { | |||
| auto src_out_anchor = in_data_anchor->GetPeerOutAnchor(); | |||
| GE_CHECK_NOTNULL(src_out_anchor); | |||
| @@ -397,25 +338,10 @@ Status HybridModelBuilder::MergeNetOutputNode(ComputeGraph &graph) { | |||
| } | |||
| } | |||
| // transfer out control edges | |||
| std::set<NodePtr> in_node_set(all_in_nodes.begin(), all_in_nodes.end()); | |||
| std::set<NodePtr> out_node_set(all_out_nodes.begin(), all_out_nodes.end()); | |||
| for (auto &src_node : in_node_set) { | |||
| GELOGD("[%s] process in node.", src_node->GetName().c_str()); | |||
| auto out_nodes = src_node->GetOutAllNodes(); | |||
| std::set<NodePtr> node_set(out_nodes.begin(), out_nodes.end()); | |||
| for (auto &dst_node : out_node_set) { | |||
| if (node_set.count(dst_node) == 0) { | |||
| src_node->GetOutControlAnchor()->LinkTo(dst_node->GetInControlAnchor()); | |||
| GELOGD("[%s] Restore control edge to [%s]", src_node->GetName().c_str(), dst_node->GetName().c_str()); | |||
| } | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::UnfoldSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph) { | |||
| Status HybridModelBuilder::MergeSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph) { | |||
| merged_graph = MakeShared<ComputeGraph>("MergedGraph"); | |||
| for (const auto &node : root_graph.GetDirectNode()) { | |||
| GE_CHECK_NOTNULL(node); | |||
| @@ -445,74 +371,32 @@ Status HybridModelBuilder::UnfoldSubgraphs(ComputeGraph &root_graph, ComputeGrap | |||
| } | |||
| auto subgraph = NodeUtils::GetSubgraph(*node, kSubgraphIndex); | |||
| GE_CHECK_NOTNULL(subgraph); | |||
| GE_CHK_GRAPH_STATUS_RET(UnfoldSubgraph(root_graph, *merged_graph, *subgraph), "[%s] Failed to merge subgraph.", | |||
| subgraph->GetName().c_str()); | |||
| } | |||
| // invoke before adding subgraphs. in case modify node id in known-shaped subgraphs. | |||
| GE_CHK_GRAPH_STATUS_RET(merged_graph->TopologicalSorting(), "Failed to invoke TopologicalSorting on merged graph."); | |||
| for (auto &remained_subgraph : root_graph.GetAllSubgraphs()) { | |||
| GELOGD("Adding subgraph [%s] to merged-graph.", remained_subgraph->GetName().c_str()); | |||
| GE_CHK_GRAPH_STATUS_RET(merged_graph->AddSubgraph(remained_subgraph), "Failed to add subgraph [%s]", | |||
| remained_subgraph->GetName().c_str()); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::UnfoldSubgraph(ComputeGraph &root_graph, ComputeGraph &parent_graph, | |||
| ComputeGraph &sub_graph) { | |||
| auto parent_node = sub_graph.GetParentNode(); | |||
| GE_CHECK_NOTNULL(parent_node); | |||
| GE_CHK_STATUS_RET(MergeInputNodes(sub_graph), "[%s] Failed to merge data nodes for subgraph", | |||
| sub_graph.GetName().c_str()); | |||
| GE_CHK_STATUS_RET(MergeNetOutputNode(sub_graph), "[%s] Failed to merge net output nodes for subgraph", | |||
| sub_graph.GetName().c_str()); | |||
| GELOGD("[%s] Done merging subgraph inputs and outputs successfully.", sub_graph.GetName().c_str()); | |||
| for (auto &sub_node : sub_graph.GetDirectNode()) { | |||
| auto sub_op_type = sub_node->GetType(); | |||
| if (sub_op_type == DATA_TYPE || sub_op_type == NETOUTPUT) { | |||
| continue; | |||
| } | |||
| if (sub_op_type == CONSTANT || sub_op_type == VARIABLE) { | |||
| GELOGE(INTERNAL_ERROR, "Unexpected node in unknown subgraph. type = %s, node = %s::%s", sub_op_type.c_str(), | |||
| sub_graph.GetName().c_str(), sub_node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| if (sub_op_type == PARTITIONEDCALL) { | |||
| bool is_unknown_shape = false; | |||
| GE_CHK_GRAPH_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*sub_node, is_unknown_shape), | |||
| "[%s] Failed to invoke GetNodeUnknownShapeStatus.", sub_node->GetName().c_str()); | |||
| if (is_unknown_shape) { | |||
| auto sub_sub_graph = NodeUtils::GetSubgraph(*sub_node, kSubgraphIndex); | |||
| GE_CHECK_NOTNULL(sub_sub_graph); | |||
| GE_CHK_STATUS_RET(UnfoldSubgraph(root_graph, parent_graph, *sub_sub_graph), "[%s] Failed to merge subgraph", | |||
| sub_sub_graph->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(MergeInputNodes(*subgraph), "Failed to merge data nodes for subgraph: %s", | |||
| subgraph->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(MergeNetOutputNode(*subgraph), "Failed to merge net output nodes for subgraph: %s", | |||
| subgraph->GetName().c_str()); | |||
| GELOGD("Merging subgraph %s successfully.", subgraph->GetName().c_str()); | |||
| for (auto &sub_node : subgraph->GetAllNodes()) { | |||
| auto sub_op_type = sub_node->GetType(); | |||
| if (sub_op_type == DATA_TYPE || sub_op_type == NETOUTPUT) { | |||
| continue; | |||
| } | |||
| } | |||
| parent_graph.AddNode(sub_node); | |||
| GELOGD("[%s::%s] added to parent graph: [%s].", sub_graph.GetName().c_str(), sub_node->GetName().c_str(), | |||
| parent_graph.GetName().c_str()); | |||
| if (sub_op_type == CONSTANT || sub_op_type == CONSTANTOP || sub_op_type == VARIABLE) { | |||
| GELOGE(INTERNAL_ERROR, "Unexpected node in unknown subgraph. type = %s, node = %s::%s", sub_op_type.c_str(), | |||
| subgraph->GetName().c_str(), sub_node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| merged_graph->AddNode(sub_node); | |||
| GELOGD("%s::%s added to merged graph.", subgraph->GetName().c_str(), sub_node->GetName().c_str()); | |||
| } | |||
| } | |||
| GELOGD("[%s] Done merging subgraph. remove it from root graph.", sub_graph.GetName().c_str()); | |||
| root_graph.RemoveSubgraph(sub_graph.GetName()); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::BuildOutputMapping(GraphItem &graph_item, const NodeItem &node_item, bool is_root_graph) { | |||
| auto output_size = node_item.op_desc->GetAllInputsSize(); | |||
| GE_CHECK_LE(output_size, UINT32_MAX); | |||
| graph_item.output_edges_.resize(output_size); | |||
| Status HybridModelBuilder::ParseNetOutput(const NodeItem &node_item) { | |||
| for (auto &in_data_anchor : node_item.node->GetAllInDataAnchors()) { | |||
| auto peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); | |||
| GE_CHECK_NOTNULL(peer_out_anchor); | |||
| @@ -524,20 +408,11 @@ Status HybridModelBuilder::BuildOutputMapping(GraphItem &graph_item, const NodeI | |||
| auto output_offset = src_node_item->output_start + peer_out_anchor->GetIdx(); | |||
| GELOGI("Output[%d], node = %s, output_index = %d, output_offset = %d ", in_data_anchor->GetIdx(), | |||
| src_node_item->NodeName().c_str(), peer_out_anchor->GetIdx(), output_offset); | |||
| graph_item.output_edges_[in_data_anchor->GetIdx()] = {src_node_item, peer_out_anchor->GetIdx()}; | |||
| hybrid_model_.output_offsets_.emplace_back(output_offset); | |||
| } | |||
| if (!is_root_graph) { | |||
| for (uint32_t i = 0; i < static_cast<uint32_t>(output_size); ++i) { | |||
| uint32_t p_index = i; | |||
| // Net output of Subgraph of while do not have parent index | |||
| if (AttrUtils::GetInt(node_item.op_desc->GetInputDesc(i), ATTR_NAME_PARENT_NODE_INDEX, p_index)) { | |||
| GELOGD("[%s] Parent index not set for input[%u].", node_item.NodeName().c_str(), i); | |||
| } | |||
| graph_item.output_index_mapping_.emplace_back(p_index); | |||
| } | |||
| for (int i = 0; i < node_item.num_inputs; ++i) { | |||
| hybrid_model_.net_output_input_offsets_.emplace_back(node_item.input_start + i); | |||
| } | |||
| return SUCCESS; | |||
| @@ -545,37 +420,82 @@ Status HybridModelBuilder::BuildOutputMapping(GraphItem &graph_item, const NodeI | |||
| Status HybridModelBuilder::LoadGraph() { | |||
| auto root_graph = ge_root_model_->GetRootGraph(); | |||
| GE_CHK_STATUS_RET(LoadDynamicSubgraph(*root_graph, true), "Failed to load root graph."); | |||
| GELOGD("Done loading root graph successfully."); | |||
| for (auto &sub_graph : root_graph->GetAllSubgraphs()) { | |||
| GE_CHECK_NOTNULL(sub_graph); | |||
| GELOGD("Start to load subgraph [%s]", sub_graph->GetName().c_str()); | |||
| auto parent_node = sub_graph->GetParentNode(); | |||
| GE_CHECK_NOTNULL(parent_node); | |||
| auto parent_node_item = MutableNodeItem(parent_node); | |||
| // parent node is in another known subgraph | |||
| if (parent_node_item == nullptr) { | |||
| GELOGD("[%s] Subgraph is in another known shaped subgraph, skip it.", sub_graph->GetName().c_str()); | |||
| continue; | |||
| GELOGI("Before merge subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", root_graph->GetDirectNodesSize(), | |||
| root_graph->GetAllNodesSize()); | |||
| ComputeGraphPtr merged_graph; | |||
| GE_CHK_STATUS_RET_NOLOG(MergeSubgraphs(*root_graph, merged_graph)); | |||
| GELOGI("After merge subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", merged_graph->GetDirectNodesSize(), | |||
| merged_graph->GetAllNodesSize()); | |||
| merged_graph->SetGraphID(runtime_param_.graph_id); | |||
| GE_DUMP(merged_graph, "hybrid_merged_graph"); | |||
| int input_start = 0; | |||
| int output_start = 0; | |||
| uint32_t data_op_index = 0; | |||
| hybrid_model_.node_items_.resize(merged_graph->GetDirectNodesSize()); | |||
| int64_t node_index = 0; | |||
| for (auto &node : merged_graph->GetDirectNode()) { | |||
| OpDescPtr op_desc = node->GetOpDesc(); | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| op_desc->SetId(node_index++); | |||
| } | |||
| for (const auto &node : merged_graph->GetDirectNode()) { | |||
| GE_CHECK_NOTNULL(node); | |||
| GE_CHECK_NOTNULL(node->GetOpDesc()); | |||
| const auto &op_type = node->GetType(); | |||
| NodeItem *node_item = nullptr; | |||
| GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(node, &node_item)); | |||
| GE_CHK_STATUS_RET_NOLOG(BuildNoteItem(node, *node_item)); | |||
| GE_CHK_STATUS_RET_NOLOG(UpdateAnchorStatus(node)); // needed by FE generate task | |||
| node_item->input_start = input_start; | |||
| node_item->output_start = output_start; | |||
| input_start += node_item->num_inputs; | |||
| output_start += node_item->num_outputs; | |||
| if (op_type == DATA_TYPE || op_type == AIPP_DATA_TYPE) { | |||
| auto data_index = data_op_index; | |||
| if (AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_INDEX, data_index)) { | |||
| GELOGI("ge_train: get new index %u, old %u", data_index, data_op_index); | |||
| } | |||
| hybrid_model_.input_nodes_.emplace(data_index, node_item); | |||
| data_op_index++; | |||
| } else if (op_type == NETOUTPUT) { | |||
| hybrid_model_.net_output_node_ = node_item; | |||
| GE_CHK_STATUS_RET_NOLOG(ParseNetOutput(*node_item)); | |||
| } else if (op_type == PARTITIONEDCALL) { // known graph | |||
| GE_CHK_STATUS_RET_NOLOG(ParsePartitionedCall(*node_item)); | |||
| } | |||
| if (sub_graph->GetGraphUnknownFlag()) { | |||
| GE_CHK_STATUS_RET(LoadDynamicSubgraph(*sub_graph, false), "Failed to load subgraph: [%s]", | |||
| sub_graph->GetName().c_str()); | |||
| } else { | |||
| GE_CHK_STATUS_RET(IdentifyVariableOutputs(*parent_node_item), "[%s] Failed to identify ref outputs.", | |||
| parent_node_item->NodeName().c_str()); | |||
| GELOGI("NodeItem created: %s", node_item->DebugString().c_str()); | |||
| } | |||
| // if parent is function control op. need add a virtual partitioned call | |||
| if (parent_node_item->IsControlOp()) { | |||
| GE_CHK_STATUS_RET(LoadKnownShapedSubgraph(*sub_graph, parent_node_item), | |||
| "Failed to load function control op subgraph [%s]", sub_graph->GetName().c_str()); | |||
| for (auto &it : hybrid_model_.input_nodes_) { | |||
| auto input_index = it.first; | |||
| auto input_node = it.second; | |||
| if (input_node->outputs.empty()) { | |||
| GELOGE(INTERNAL_ERROR, "data output anchor is empty"); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| for (auto &out : input_node->outputs) { | |||
| std::vector<int> offsets; | |||
| for (auto &dst_anchor_and_node : out) { | |||
| auto dst_node_item = dst_anchor_and_node.second; | |||
| offsets.emplace_back(dst_node_item->input_start + dst_anchor_and_node.first); | |||
| } | |||
| hybrid_model_.input_offsets_.emplace(input_index, std::move(offsets)); | |||
| } | |||
| } | |||
| GELOGI("Done loading all subgraphs successfully."); | |||
| hybrid_model_.total_inputs_ = input_start; | |||
| hybrid_model_.total_outputs_ = output_start; | |||
| GELOGI("HybridGraph::LoadGraph OUT"); | |||
| return SUCCESS; | |||
| } | |||
| @@ -587,6 +507,7 @@ Status HybridModelBuilder::VarNodeToTensor(const NodePtr &var_node, std::unique_ | |||
| string var_name = var_node->GetName(); | |||
| auto tensor_desc = var_node->GetOpDesc()->MutableOutputDesc(0); | |||
| uint8_t *var_logic = nullptr; | |||
| GE_CHK_STATUS_RET(var_manager_->GetVarAddr(var_name, *tensor_desc, &var_logic), | |||
| "Failed to get var addr. var_name = %s, session_id = %ld", var_name.c_str(), | |||
| hybrid_model_.GetSessionId()); | |||
| @@ -638,26 +559,10 @@ Status HybridModelBuilder::HandleDtString(const GeTensor &tensor, void *var_addr | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::AssignUninitializedConstantOps() { | |||
| for (auto &it : hybrid_model_.constant_op_nodes_) { | |||
| const string &var_name = it.first; | |||
| const NodePtr &var_node = it.second; | |||
| auto tensor_desc = var_node->GetOpDesc()->MutableOutputDesc(0); | |||
| if (!var_manager_->IsVarExist(var_name, *tensor_desc)) { | |||
| // allocate constant | |||
| GELOGD("[%s] Constant not allocated during graph building. now allocate it.", var_name.c_str()); | |||
| GE_CHK_STATUS_RET(var_manager_->AssignVarMem(var_name, *tensor_desc, RT_MEMORY_HBM)); | |||
| GE_CHK_STATUS_RET(var_manager_->SetAllocatedGraphId(var_name, runtime_param_.graph_id)); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::InitConstantOps() { | |||
| for (auto &it : hybrid_model_.constant_op_nodes_) { | |||
| const string &var_name = it.first; | |||
| const NodePtr &var_node = it.second; | |||
| string var_name = it.first; | |||
| NodePtr &var_node = it.second; | |||
| std::unique_ptr<TensorValue> var_tensor; | |||
| GE_CHK_STATUS_RET_NOLOG(VarNodeToTensor(var_node, var_tensor)); | |||
| @@ -673,7 +578,7 @@ Status HybridModelBuilder::InitConstantOps() { | |||
| if (ge_tensor->GetData().size() > 0) { | |||
| GE_CHK_STATUS_RET_NOLOG(HandleDtString(*ge_tensor, v_output_addr)); | |||
| GELOGI("[IMAS]InitConstant memcpy graph_%u type[V] name[%s] output[%d] memaddr[%p] mem_size[%zu] datasize[%zu]", | |||
| GELOGI("[IMAS]InitConstant memcpy graph_%u type[V] name[%s] output[%d] memaddr[%p] mem_size[%u] datasize[%zu]", | |||
| runtime_param_.graph_id, op_desc->GetName().c_str(), 0, v_output_addr, v_output_size, | |||
| ge_tensor->GetData().size()); | |||
| GE_CHK_RT_RET(rtMemcpy(v_output_addr, v_output_size, ge_tensor->GetData().data(), ge_tensor->GetData().size(), | |||
| @@ -709,8 +614,7 @@ Status HybridModelBuilder::InitWeights() { | |||
| } | |||
| Status HybridModelBuilder::LoadTasks() { | |||
| for (auto &it : hybrid_model_.node_items_) { | |||
| auto &node_item = it.second; | |||
| for (auto &node_item : hybrid_model_.node_items_) { | |||
| auto &node_ptr = node_item->node; | |||
| if (node_item->node_type == NETOUTPUT) { | |||
| continue; | |||
| @@ -718,6 +622,7 @@ Status HybridModelBuilder::LoadTasks() { | |||
| GELOGD("[%s] Start to build kernel task", node_ptr->GetName().c_str()); | |||
| auto load_ret = node_item->node_executor->LoadTask(hybrid_model_, node_ptr, node_item->kernel_task); | |||
| if (load_ret != UNSUPPORTED && load_ret != SUCCESS) { | |||
| GELOGE(load_ret, "[%s] Failed to load task", node_ptr->GetName().c_str()); | |||
| return load_ret; | |||
| @@ -729,23 +634,6 @@ Status HybridModelBuilder::LoadTasks() { | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::LoadGeModel(ComputeGraph &sub_graph, const GeModelPtr &ge_model) { | |||
| auto parent_node = sub_graph.GetParentNode(); | |||
| GE_CHECK_NOTNULL(parent_node); | |||
| auto op_type = parent_node->GetType(); | |||
| if (op_type == IF || op_type == CASE || op_type == WHILE) { | |||
| GELOGD("Set ge_model for control op subgraph: [%s], task_size = %d", sub_graph.GetName().c_str(), | |||
| ge_model->GetModelTaskDefPtr()->task_size()); | |||
| subgraph_models_.emplace(sub_graph.GetName(), ge_model); | |||
| } else { | |||
| GELOGD("Set ge_model for subgraph: [%s], task_size = %d", sub_graph.GetName().c_str(), | |||
| ge_model->GetModelTaskDefPtr()->task_size()); | |||
| hybrid_model_.known_shape_sub_models_.emplace(sub_graph.GetParentNode(), ge_model); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::IndexTaskDefs() { | |||
| const auto &root_graph = ge_root_model_->GetRootGraph(); | |||
| for (auto &it : ge_root_model_->GetSubgraphInstanceNameToModel()) { | |||
| @@ -758,9 +646,12 @@ Status HybridModelBuilder::IndexTaskDefs() { | |||
| continue; | |||
| } | |||
| bool is_unknown_shape = sub_graph->GetGraphUnknownFlag(); | |||
| bool is_unknown_shape = false; | |||
| GE_CHK_GRAPH_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*sub_graph->GetParentNode(), is_unknown_shape), | |||
| "Failed to invoke GetNodeUnknownShapeStatus."); | |||
| if (!is_unknown_shape) { | |||
| GE_CHK_STATUS_RET_NOLOG(LoadGeModel(*sub_graph, ge_model)); | |||
| GELOGD("Set ge_model for subgraph: %s", sub_graph->GetName().c_str()); | |||
| hybrid_model_.known_shape_sub_graphs_.emplace(sub_graph->GetParentNode(), ge_model); | |||
| continue; | |||
| } | |||
| @@ -785,8 +676,6 @@ Status HybridModelBuilder::IndexTaskDefs() { | |||
| op_index = task_def.kernel().context().op_index(); | |||
| } else if (task_type == RT_MODEL_TASK_KERNEL_EX) { | |||
| op_index = task_def.kernel_ex().op_index(); | |||
| } else if (task_type == RT_MODEL_TASK_HCCL) { | |||
| op_index = task_def.kernel_hccl().op_index(); | |||
| } else { | |||
| GELOGD("Skip task type: %d", static_cast<int>(task_type)); | |||
| continue; | |||
| @@ -901,12 +790,12 @@ Status HybridModelBuilder::GetPeerNodeAcrossSubGraphs(const NodePtr &data_node, | |||
| for (uint32_t i = 0; i < static_cast<uint32_t>(input_size); ++i) { | |||
| uint32_t p_index = 0; | |||
| if (!AttrUtils::GetInt(net_output_desc->GetInputDesc(i), ATTR_NAME_PARENT_NODE_INDEX, p_index)) { | |||
| GELOGW("SubGraph: %s input tensor %u attr %s not found.", src_graph->GetName().c_str(), i, | |||
| GELOGW("SubGraph: %s input tensor %zu attr %s not found.", src_graph->GetName().c_str(), i, | |||
| ATTR_NAME_PARENT_NODE_INDEX.c_str()); | |||
| continue; | |||
| } | |||
| GELOGD("NetOutput's input[%u], parent_node_index = %u", i, p_index); | |||
| GELOGD("NetOutput's input[%zu], parent_node_index = %u", i, p_index); | |||
| if (p_index == out_index) { | |||
| auto in_anchor = src_net_output_node->GetInDataAnchor(i); | |||
| GE_CHECK_NOTNULL(in_anchor); | |||
| @@ -941,7 +830,7 @@ Status HybridModelBuilder::InitRuntimeParams() { | |||
| ret = ge::AttrUtils::GetInt(first_model, ATTR_MODEL_VAR_SIZE, value); | |||
| runtime_param_.var_size = ret ? (uint64_t)value : 0; | |||
| runtime_param_.graph_id = ge_root_model_->GetRootGraph()->GetGraphID(); | |||
| GELOGI("InitRuntimeParams(), session_id:%lu, var_size:%lu. graph_id = %u", runtime_param_.session_id, | |||
| GELOGI("InitRuntimeParams(), session_id:%u, var_size:%lu. graph_id = %u", runtime_param_.session_id, | |||
| runtime_param_.var_size, runtime_param_.graph_id); | |||
| var_manager_ = VarManager::Instance(runtime_param_.session_id); | |||
| @@ -949,7 +838,7 @@ Status HybridModelBuilder::InitRuntimeParams() { | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::IdentifyVariableOutputs(NodeItem &node_item) { | |||
| Status HybridModelBuilder::ParsePartitionedCall(NodeItem &node_item) { | |||
| GELOGD("Start to parse outputs of node: %s", node_item.NodeName().c_str()); | |||
| auto subgraph = NodeUtils::GetSubgraph(*node_item.node, kSubgraphIndex); | |||
| GE_CHECK_NOTNULL(subgraph); | |||
| @@ -958,7 +847,6 @@ Status HybridModelBuilder::IdentifyVariableOutputs(NodeItem &node_item) { | |||
| auto net_output_desc = net_output_node->GetOpDesc(); | |||
| GE_CHECK_NOTNULL(net_output_desc); | |||
| // constant/variable connected to net output | |||
| for (const auto &in_data_anchor : net_output_node->GetAllInDataAnchors()) { | |||
| auto src_node = GetPeerNode(in_data_anchor); | |||
| GE_CHECK_NOTNULL(src_node); | |||
| @@ -976,8 +864,6 @@ Status HybridModelBuilder::IdentifyVariableOutputs(NodeItem &node_item) { | |||
| node_item.ref_outputs.emplace(parent_index, src_node); | |||
| } | |||
| // Data nodes marked with REF_VAR_SRC_VAR_NAME | |||
| // Using variable tensor as data's output | |||
| for (auto &node : subgraph->GetDirectNode()) { | |||
| if (node->GetType() != DATA) { | |||
| continue; | |||
| @@ -1026,11 +912,6 @@ Status HybridModelBuilder::GetParentNodeOutputIndex(const OpDesc &op_desc, int i | |||
| Status HybridModelBuilder::InitModelMem() { | |||
| hybrid_model_.var_mem_base_ = var_manager_->GetVarMemoryBase(RT_MEMORY_HBM); | |||
| auto total_var_size = hybrid_model_.TotalVarMemSize(); | |||
| if (total_var_size == 0 && !hybrid_model_.constant_op_nodes_.empty()) { | |||
| total_var_size = var_manager_->GetVarMemSize(RT_MEMORY_HBM) > 0 ? var_manager_->GetVarMemMaxSize() : 0; | |||
| GELOGD("Model var size = 0. but got uninitialized constant. set var size to %zu.", total_var_size); | |||
| } | |||
| if (total_var_size > 0 && hybrid_model_.var_mem_base_ == nullptr) { | |||
| GE_CHK_STATUS_RET(var_manager_->MallocVarMemory(total_var_size), "Malloc Var Memory Fail."); | |||
| hybrid_model_.var_mem_base_ = var_manager_->GetVarMemoryBase(RT_MEMORY_HBM); | |||
| @@ -1070,154 +951,5 @@ Status HybridModelBuilder::CopyVarData() { | |||
| GELOGI("CopyVarData success."); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::LoadKnownShapedSubgraph(ComputeGraph &graph, NodeItem *parent_node_item) { | |||
| GELOGD("Start to load known shaped subgraph [%s]", graph.GetName().c_str()); | |||
| auto graph_item = std::unique_ptr<GraphItem>(new (std::nothrow) GraphItem()); | |||
| GE_CHECK_NOTNULL(graph_item); | |||
| graph_item->is_dynamic_ = false; | |||
| auto subgraph_name = graph.GetName(); | |||
| auto wrapper_op_desc = MakeShared<OpDesc>(subgraph_name + "_partitioned_call", PARTITIONEDCALL); | |||
| GE_CHECK_NOTNULL(wrapper_op_desc); | |||
| for (auto &node : graph.GetDirectNode()) { | |||
| GE_CHECK_NOTNULL(node); | |||
| auto op_desc = node->GetOpDesc(); | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| const auto &op_type = node->GetType(); | |||
| if (op_type == DATA) { | |||
| int32_t data_index = 0; | |||
| if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, data_index)) { | |||
| GELOGE(FAILED, "[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); | |||
| return FAILED; | |||
| } | |||
| (void)wrapper_op_desc->AddInputDesc(op_desc->GetInputDesc(0)); | |||
| graph_item->input_index_mapping_.emplace_back(data_index); | |||
| } else if (op_type == NETOUTPUT) { | |||
| int output_index = 0; | |||
| for (const auto &output_desc : op_desc->GetAllInputsDescPtr()) { | |||
| int32_t data_index = output_index++; | |||
| if (!AttrUtils::GetInt(output_desc, ATTR_NAME_PARENT_NODE_INDEX, data_index)) { | |||
| GELOGI("[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); | |||
| } | |||
| GE_CHK_GRAPH_STATUS_RET(wrapper_op_desc->AddOutputDesc(*output_desc), | |||
| "[%s] Failed to add output desc. output index = %d", graph.GetName().c_str(), | |||
| output_index); | |||
| graph_item->output_index_mapping_.emplace_back(data_index); | |||
| } | |||
| } | |||
| } | |||
| auto temp_graph = MakeShared<ComputeGraph>("temp"); | |||
| GE_CHECK_NOTNULL(temp_graph); | |||
| auto wrapper_node = temp_graph->AddNode(wrapper_op_desc); | |||
| GeModelPtr ge_model = subgraph_models_[subgraph_name]; | |||
| GE_CHECK_NOTNULL(ge_model); | |||
| hybrid_model_.known_shape_sub_models_.emplace(wrapper_node, ge_model); | |||
| NodeItem *node_item = nullptr; | |||
| GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(wrapper_node, &node_item)); | |||
| node_item->input_start = 0; | |||
| node_item->output_start = 0; | |||
| node_item->outputs.resize(node_item->num_outputs); | |||
| graph_item->node_items_.emplace_back(node_item); | |||
| graph_item->output_node_ = node_item; | |||
| graph_item->total_inputs_ = node_item->num_inputs; | |||
| graph_item->total_outputs_ = node_item->num_outputs; | |||
| GELOGD("NodeItem create for known shape subgraph [%s], NodeItem = %s", graph.GetName().c_str(), | |||
| node_item->DebugString().c_str()); | |||
| GELOGD("Done parse known shape subgraph successfully. graph = [%s]", graph.GetName().c_str()); | |||
| graph_item->SetName(graph.GetName()); | |||
| GELOGD("Done loading known shape subgraph: [%s]", graph_item->GetName().c_str()); | |||
| hybrid_model_.subgraph_items_.emplace(graph.GetName(), std::move(graph_item)); | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::LoadDynamicSubgraph(ComputeGraph &graph, bool is_root_graph) { | |||
| GELOGD("Start to load subgraph [%s]", graph.GetName().c_str()); | |||
| // for known partitioned call, load all nodes | |||
| auto graph_item = std::unique_ptr<GraphItem>(new (std::nothrow) GraphItem()); | |||
| GE_CHECK_NOTNULL(graph_item); | |||
| graph_item->is_dynamic_ = true; | |||
| graph_item->node_items_.reserve(graph.GetDirectNodesSize()); | |||
| int input_start = 0; | |||
| int output_start = 0; | |||
| std::vector<NodeItem *> data_nodes; | |||
| for (auto &node : graph.GetDirectNode()) { | |||
| GE_CHECK_NOTNULL(node); | |||
| GE_CHECK_NOTNULL(node->GetOpDesc()); | |||
| const auto &op_type = node->GetType(); | |||
| NodeItem *node_item = nullptr; | |||
| GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(node, &node_item)); | |||
| GE_CHK_STATUS_RET_NOLOG(BuildNodeItem(node, *node_item)); | |||
| GE_CHK_STATUS_RET_NOLOG(UpdateAnchorStatus(node)); // needed by FE generate task | |||
| node_item->input_start = input_start; | |||
| node_item->output_start = output_start; | |||
| input_start += node_item->num_inputs; | |||
| output_start += node_item->num_outputs; | |||
| if (op_type == DATA_TYPE || op_type == AIPP_DATA_TYPE) { | |||
| data_nodes.emplace_back(node_item); | |||
| } else if (op_type == NETOUTPUT) { | |||
| graph_item->output_node_ = node_item; | |||
| GE_CHK_STATUS_RET_NOLOG(BuildOutputMapping(*graph_item, *node_item, is_root_graph)); | |||
| } | |||
| graph_item->node_items_.emplace_back(node_item); | |||
| GELOGD("NodeItem created: %s", node_item->DebugString().c_str()); | |||
| } | |||
| graph_item->total_inputs_ = input_start; | |||
| graph_item->total_outputs_ = output_start; | |||
| GE_CHK_STATUS_RET_NOLOG(BuildInputMapping(*graph_item, data_nodes, is_root_graph)); | |||
| if (is_root_graph) { | |||
| graph_item->SetName("Root-Graph"); | |||
| GELOGD("Done loading dynamic subgraph: [%s]", graph_item->GetName().c_str()); | |||
| hybrid_model_.root_graph_item_ = std::move(graph_item); | |||
| } else { | |||
| graph_item->SetName(graph.GetName()); | |||
| GELOGD("Done loading dynamic subgraph: [%s]", graph_item->GetName().c_str()); | |||
| hybrid_model_.subgraph_items_.emplace(graph.GetName(), std::move(graph_item)); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HybridModelBuilder::BuildInputMapping(GraphItem &graph_item, vector<NodeItem *> &data_nodes, | |||
| bool is_root_graph) { | |||
| uint32_t data_op_index = 0; | |||
| for (auto &node_item : data_nodes) { | |||
| auto node = node_item->node; | |||
| int data_index = data_op_index; | |||
| if (is_root_graph) { | |||
| if (AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_INDEX, data_index)) { | |||
| GELOGI("ge_train: get new index %u, old %u", data_index, data_op_index); | |||
| } | |||
| data_op_index++; | |||
| } else { | |||
| if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, data_index)) { | |||
| GELOGE(FAILED, "[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); | |||
| return FAILED; | |||
| } | |||
| } | |||
| if (graph_item.input_nodes_.size() <= static_cast<size_t>(data_index)) { | |||
| graph_item.input_nodes_.resize(data_index + 1); | |||
| } | |||
| graph_item.input_nodes_[data_index] = node_item; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -46,20 +46,18 @@ class HybridModelBuilder { | |||
| static Status HandleDtString(const GeTensor &tensor, void *var_addr); | |||
| static Status MergeInputNodes(ComputeGraph &compute_graph); | |||
| static Status MergeNetOutputNode(ComputeGraph &compute_graph); | |||
| static Status UnfoldSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph); | |||
| static Status UnfoldSubgraph(ComputeGraph &root_graph, ComputeGraph &parent_graph, ComputeGraph &sub_graph); | |||
| static Status MergeSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph); | |||
| static Status InitWeights(); | |||
| static Status BuildInputMapping(GraphItem &graph_item, std::vector<NodeItem *> &data_nodes, bool is_root_graph); | |||
| static Status ResolveRefIo(NodeItem &node_item); | |||
| Status BuildOutputMapping(GraphItem &partitioned_call, const NodeItem &node_item, bool is_root_graph); | |||
| Status ValidateParams(); | |||
| Status LoadGraph(); | |||
| Status LoadGeModel(ComputeGraph &graph, const GeModelPtr &ge_model); | |||
| Status LoadTasks(); | |||
| Status IdentifyVariableOutputs(NodeItem &node_item); | |||
| Status BuildNodeItem(const NodePtr &node, NodeItem &node_item); | |||
| Status ParsePartitionedCall(NodeItem &node_item); | |||
| Status ParseNetOutput(const NodeItem &node_item); | |||
| Status BuildNoteItem(const NodePtr &node, NodeItem &node_item); | |||
| Status GetOrCreateNodeItem(const NodePtr &node, NodeItem **node_item); | |||
| Status ParseDependentInputNodes(NodeItem &node_item, const std::vector<string> &dependencies); | |||
| Status ResolveRootNodes(); | |||
| Status IndexTaskDefs(); | |||
| Status IndexSpecialNodes(); | |||
| Status InitRuntimeParams(); | |||
| @@ -67,23 +65,19 @@ class HybridModelBuilder { | |||
| Status TransAllVarData(); | |||
| Status CopyVarData(); | |||
| Status VarNodeToTensor(const NodePtr &var_node, std::unique_ptr<TensorValue> &tensor); | |||
| Status AssignUninitializedConstantOps(); | |||
| Status InitConstantOps(); | |||
| Status InitVariableTensors(); | |||
| Status LoadDynamicSubgraph(ComputeGraph &graph, bool is_root_graph); | |||
| Status LoadKnownShapedSubgraph(ComputeGraph &graph, NodeItem *parent_node_item); | |||
| const char *GetGraphName() const { return hybrid_model_.model_name_.c_str(); } | |||
| const char *GetGraphName() const { return graph_name_.c_str(); } | |||
| const NodeItem *GetNodeItem(const NodePtr &node) const; | |||
| NodeItem *MutableNodeItem(const NodePtr &node); | |||
| GeRootModelPtr ge_root_model_; | |||
| std::string graph_name_; | |||
| std::map<int, std::unique_ptr<TensorValue>> weights_; | |||
| std::map<std::string, GeModelPtr> subgraph_models_; | |||
| HybridModel &hybrid_model_; | |||
| std::map<NodePtr, std::vector<std::pair<int, NodePtr>>> node_ref_inputs_; | |||
| int node_index = 0; | |||
| RuntimeParam &runtime_param_; | |||
| VarManager *var_manager_ = nullptr; | |||
| @@ -16,8 +16,6 @@ | |||
| #include "node_item.h" | |||
| #include <sstream> | |||
| #include "common/debug/log.h" | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| @@ -30,34 +28,12 @@ NodeItem::NodeItem(NodePtr node) : node(std::move(node)) { | |||
| this->node_type = this->node->GetType(); | |||
| } | |||
| Status NodeItem::Init() { | |||
| for (int i = 0; i < num_inputs; ++i) { | |||
| const auto &input_desc = op_desc->MutableInputDesc(i); | |||
| GE_CHECK_NOTNULL(input_desc); | |||
| if (input_desc->MutableShape().IsUnknownShape()) { | |||
| is_input_shape_static.push_back(false); | |||
| } else { | |||
| num_static_input_shapes++; | |||
| is_input_shape_static.push_back(true); | |||
| GELOGD("[%s] The shape of input[%d] is static. shape = [%s]", NodeName().c_str(), i, | |||
| input_desc->MutableShape().ToString().c_str()); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| bool NodeItem::IsControlOp() const { | |||
| auto op_type = op_desc->GetType(); | |||
| return op_type == IF || op_type == CASE || op_type == WHILE || op_type == FOR; | |||
| } | |||
| std::string NodeItem::DebugString() const { | |||
| std::stringstream ss; | |||
| ss << "Node: "; | |||
| ss << "id = " << node_id; | |||
| ss << ", name = [" << node->GetName(); | |||
| ss << "], type = " << node->GetType(); | |||
| ss << ", name = " << node->GetName(); | |||
| ss << ", type = " << node->GetType(); | |||
| ss << ", is_dynamic = " << (is_dynamic ? "True" : "False"); | |||
| ss << ", unknown_shape_op_type = " << shape_inference_type; | |||
| ss << ", input_start = " << input_start; | |||
| @@ -65,7 +41,7 @@ std::string NodeItem::DebugString() const { | |||
| ss << ", output_start = " << output_start; | |||
| ss << ", num_outputs = " << num_outputs; | |||
| ss << ", dependent_nodes = ["; | |||
| for (const auto &dep_node : dependents_for_shape_inference) { | |||
| for (const auto &dep_node : dependent_node_list) { | |||
| ss << dep_node->GetName() << ", "; | |||
| } | |||
| ss << "]"; | |||
| @@ -79,18 +55,5 @@ std::string NodeItem::DebugString() const { | |||
| return ss.str(); | |||
| } | |||
| void NodeItem::SetToDynamic() { | |||
| num_static_input_shapes = 0; | |||
| is_dynamic = true; | |||
| for (size_t i = 0; i < is_input_shape_static.size(); ++i) { | |||
| is_input_shape_static[i] = false; | |||
| } | |||
| if (kernel_task != nullptr && !kernel_task->IsSupportDynamicShape()) { | |||
| GELOGD("[%s] Dynamic shape is not supported, clear node task.", node_name.c_str()); | |||
| kernel_task = nullptr; | |||
| } | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -18,7 +18,6 @@ | |||
| #define GE_HYBRID_MODEL_NODE_ITEM_H_ | |||
| #include <vector> | |||
| #include "external/ge/ge_api_error_codes.h" | |||
| #include "graph/node.h" | |||
| #include "graph/op_desc.h" | |||
| #include "framework/common/types.h" | |||
| @@ -34,16 +33,10 @@ struct NodeItem { | |||
| explicit NodeItem(NodePtr node); | |||
| ~NodeItem() = default; | |||
| Status Init(); | |||
| const std::string &NodeName() const { return node_name; } | |||
| const std::string &NodeType() const { return node_type; } | |||
| bool IsControlOp() const; | |||
| void SetToDynamic(); | |||
| std::string DebugString() const; | |||
| NodePtr node; | |||
| @@ -59,21 +52,17 @@ struct NodeItem { | |||
| UnknowShapeOpType shape_inference_type = DEPEND_IN_SHAPE; | |||
| std::string node_name; | |||
| std::string node_type; | |||
| std::vector<ge::NodePtr> dependents_for_shape_inference; | |||
| std::vector<ge::NodePtr> dependents_for_execution; | |||
| std::vector<ge::NodePtr> dependent_node_list; | |||
| std::set<int> to_const_output_id_list; | |||
| vector<NodeItem *> inputs; | |||
| // src_output_id, dst_anchor_id, dst_node | |||
| vector<NodeItem *> inputs; | |||
| vector<vector<pair<uint32_t, NodeItem *>>> outputs; | |||
| std::shared_ptr<NodeTask> kernel_task; | |||
| const NodeExecutor *node_executor = nullptr; | |||
| std::map<int, ge::GeTensorDescPtr> const_input_shapes; | |||
| std::map<int, ge::NodePtr> ref_outputs; | |||
| std::map<int, int> reuse_inputs; | |||
| std::vector<bool> is_input_shape_static; | |||
| int num_static_input_shapes = 0; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -16,8 +16,10 @@ | |||
| #include "aicore_node_executor.h" | |||
| #include "cce/taskdown_common.hpp" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "graph/debug/ge_attr_define.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| #include "init/gelib.h" | |||
| #include "framework/common/debug/log.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| @@ -25,47 +27,16 @@ REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::AICORE, AiCore | |||
| AiCoreNodeTask::AiCoreNodeTask(std::vector<std::unique_ptr<AiCoreOpTask>> &&tasks) : tasks_(std::move(tasks)) {} | |||
| Status AiCoreNodeExecutor::Initialize() { | |||
| auto ge_lib = GELib::GetInstance(); | |||
| GE_CHECK_NOTNULL(ge_lib); | |||
| if (!ge_lib->InitFlag()) { | |||
| GELOGE(GE_CLI_GE_NOT_INITIALIZED, "Ge_lib is uninitialized, failed."); | |||
| return GE_CLI_GE_NOT_INITIALIZED; | |||
| } | |||
| auto &kernel_manager = ge_lib->OpsKernelManagerObj(); | |||
| auto aic_ops_store = kernel_manager.GetOpsKernelInfoStore("AIcoreEngine"); | |||
| GE_CHECK_NOTNULL(aic_ops_store); | |||
| compiler_.reset(new (std::nothrow) AiCoreTaskCompiler(aic_ops_store)); | |||
| GE_CHECK_NOTNULL(compiler_); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const { | |||
| GE_CHECK_NOTNULL(node); | |||
| GELOGI("AiCoreNodeExecutor(%s) LoadTask Start.", node->GetName().c_str()); | |||
| GELOGI("AiCoreNodeExecutor[%s] LoadTask Start.", node->GetName().c_str()); | |||
| auto *task_defs = model.GetTaskDefs(node); | |||
| if (task_defs == nullptr || task_defs->empty()) { | |||
| bool dynamic_flag = false; | |||
| if (!AttrUtils::GetBool(node->GetOpDesc(), "support_dynamicshape", dynamic_flag) || !dynamic_flag) { | |||
| GELOGD("Skip create task of node (%s) as 'support_dynamicshape' is false and cann't get task_defs.", | |||
| node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } else { | |||
| GELOGE(FAILED, "Task_defs is empty for node (%s) which 'support_dynamicshape' is true, failed.", | |||
| node->GetName().c_str()); | |||
| return FAILED; | |||
| } | |||
| } | |||
| Status ret = SUCCESS; | |||
| GE_IF_BOOL_EXEC(task_defs != nullptr && !task_defs->empty(), ret = CreateTask(model, *task_defs, node, task)); | |||
| AiCoreTaskBuilder builder(node->GetOpDesc(), *task_defs); | |||
| std::unique_ptr<NodeTask> node_task; | |||
| GE_CHK_STATUS_RET(builder.BuildTask(node_task, true), "[%s] Failed to build op tasks.", node->GetName().c_str()); | |||
| task = std::move(node_task); | |||
| GELOGI("AiCoreNodeExecutor(%s) LoadTask End.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| GELOGI("AiCoreNodeExecutor[%s] LoadTask End, ret[%u].", node->GetName().c_str(), ret); | |||
| return ret; | |||
| } | |||
| Status AiCoreNodeExecutor::GenNodeKey(const NodePtr &node, std::string &node_key) { | |||
| @@ -76,19 +47,16 @@ Status AiCoreNodeExecutor::GenNodeKey(const NodePtr &node, std::string &node_key | |||
| // make sure unique, (op_id + input_shape) is unique | |||
| node_key = std::to_string(op_desc->GetId()) + "/"; | |||
| node_key.append(std::to_string(op_desc->GetInputsSize())); | |||
| auto input_descs = op_desc->GetAllInputsDescPtr(); | |||
| for (auto &input_desc : input_descs) { | |||
| auto input_descs = op_desc->GetAllInputsDesc(); | |||
| for (auto input_desc : input_descs) { | |||
| node_key.push_back('/'); | |||
| auto &shape = input_desc->MutableShape(); | |||
| auto num_dims = shape.GetDimNum(); | |||
| if (num_dims == 0) { | |||
| continue; | |||
| } // scalar | |||
| for (std::size_t i = 0; i < num_dims - 1; i++) { | |||
| node_key.append(std::to_string(shape.GetDim(i))); | |||
| std::vector<int64_t> dims = input_desc.GetShape().GetDims(); | |||
| GE_IF_BOOL_EXEC(dims.size() == 0, continue); // scalar | |||
| for (std::size_t i = 0; i < dims.size() - 1; i++) { | |||
| node_key.append(std::to_string(dims[i])); | |||
| node_key.push_back(','); | |||
| } | |||
| node_key.append(std::to_string(shape.GetDim(num_dims - 1))); | |||
| node_key.append(std::to_string(dims[dims.size() - 1])); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| @@ -97,10 +65,8 @@ bool AiCoreNodeTaskRegistry::AddTask(const std::string &node_key, const std::sha | |||
| GE_CHECK_NOTNULL(task); | |||
| std::lock_guard<std::mutex> lock(mutex_); | |||
| auto iter = reg_node_tasks_.find(node_key); | |||
| if (iter != reg_node_tasks_.end()) { | |||
| GELOGE(FAILED, "AiCoreNodeTaskRegistry(%s) AddTask failed, key already exist.", node_key.c_str()); | |||
| return false; | |||
| } | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(iter != reg_node_tasks_.end(), return false, | |||
| "AiCoreNodeTaskRegistry[%s] AddTask failed, key already exist.", node_key.c_str()); | |||
| auto ret = reg_node_tasks_.emplace(node_key, task); | |||
| return ret.second; | |||
| } | |||
| @@ -114,84 +80,231 @@ std::shared_ptr<NodeTask> AiCoreNodeTaskRegistry::GetTask(const std::string &nod | |||
| Status AiCoreNodeExecutor::CompileTask(const HybridModel &model, const NodePtr &node, | |||
| shared_ptr<NodeTask> &task) const { | |||
| GE_CHECK_NOTNULL(node); | |||
| GELOGI("AiCoreNodeExecutor(%s) CompileTask Start.", node->GetName().c_str()); | |||
| GELOGI("AiCoreNodeExecutor[%s] CompileTask Start.", node->GetName().c_str()); | |||
| AiCoreNodeTaskRegistry ®istry = AiCoreNodeTaskRegistry::GetInstance(); | |||
| std::string node_key; | |||
| GE_CHK_STATUS_RET(GenNodeKey(node, node_key), "GenNodeKey failed, op name = %s.", node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(GenNodeKey(node, node_key), "GenNodeKey failed. op name = %s", node->GetName().c_str()); | |||
| node_key = std::to_string(model.GetModelId()) + "/" + node_key; | |||
| GELOGD("NodeKey for %s = %s", node->GetName().c_str(), node_key.c_str()); | |||
| task = registry.GetTask(node_key); | |||
| if (task != nullptr) { | |||
| GELOGI("AiCoreNodeExecutor(%s) CompileTask Skip.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| GE_CHK_TRUE_EXEC_INFO(task != nullptr, return SUCCESS, "AiCoreNodeExecutor[%s] CompileTask Skip.", | |||
| node->GetName().c_str()); | |||
| std::vector<domi::TaskDef> task_defs; | |||
| GE_CHK_STATUS_RET(compiler_->CompileOp(node, task_defs), "Compile op(%s) failed.", node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET_NOLOG(compiler_->CompileOp(node, task_defs)); | |||
| GELOGD("successfully generated task_defs: %s", node->GetName().c_str()); | |||
| AiCoreTaskBuilder builder(node->GetOpDesc(), task_defs); | |||
| std::unique_ptr<NodeTask> node_task; | |||
| GE_CHK_STATUS_RET(builder.BuildTask(node_task, false), "[%s] Failed to build op tasks.", node->GetName().c_str()); | |||
| task = std::move(node_task); | |||
| GE_CHK_STATUS_RET_NOLOG(CreateTask(model, task_defs, node, task)); | |||
| GELOGD("successfully created node task: %s", node->GetName().c_str()); | |||
| if (!registry.AddTask(node_key, task)) { | |||
| GELOGE(INTERNAL_ERROR, "Add NodeTask failed, op name = %s.", node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| GE_CHK_BOOL_EXEC(registry.AddTask(node_key, task), return INTERNAL_ERROR, "Add NodeTask failed. op name = %s", | |||
| node->GetName().c_str()); // should not happen. | |||
| GELOGI("AiCoreNodeExecutor[%s] CompileTask End.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeExecutor::BuildAiCoreTask(const domi::KernelDef &kernel_def, const OpDescPtr &op_desc, | |||
| AiCoreOpTask **task) { | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| GE_CHECK_NOTNULL(task); | |||
| const auto &context = kernel_def.context(); | |||
| auto kernel_type = static_cast<cce::ccKernelType>(context.kernel_type()); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(kernel_type != cce::ccKernelType::TE, return UNSUPPORTED, | |||
| "Only TBE kernel is supported, but [%s] got %u", op_desc->GetName().c_str(), | |||
| context.kernel_type()); | |||
| auto *aicore_task = new (std::nothrow) AiCoreOpTask(); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aicore_task == nullptr, return MEMALLOC_FAILED, "Create AiCore op task failed."); | |||
| auto builder = AiCoreTaskBuilder(op_desc, kernel_def); | |||
| auto ret = builder.BuildTask(*aicore_task); | |||
| GE_IF_BOOL_EXEC(ret != SUCCESS, delete aicore_task; aicore_task = nullptr; return ret); | |||
| *task = aicore_task; | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeExecutor::CreateTask(const HybridModel &model, const std::vector<domi::TaskDef> &task_defs, | |||
| const NodePtr &node, std::shared_ptr<NodeTask> &task) { | |||
| GE_CHECK_NOTNULL(node); | |||
| GELOGD("To CreateTask, task def size = %zu", task_defs.size()); | |||
| std::vector<std::unique_ptr<AiCoreOpTask>> aicore_op_tasks; | |||
| aicore_op_tasks.reserve(task_defs.size()); | |||
| for (size_t i = 0; i < task_defs.size(); ++i) { | |||
| const domi::TaskDef &task_def = task_defs[i]; | |||
| GELOGD("Op[%s] Task[%d], type = %u, DebugString = %s", node->GetName().c_str(), i, task_def.type(), | |||
| task_def.DebugString().c_str()); | |||
| auto task_type = static_cast<rtModelTaskType_t>(task_def.type()); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(task_type == RT_MODEL_TASK_KERNEL_EX, return UNSUPPORTED, | |||
| "BuildKernelExTask is not supported"); | |||
| GE_CHK_BOOL_TRUE_EXEC_INFO(task_type != RT_MODEL_TASK_KERNEL, continue, "Skip task type %d", | |||
| static_cast<int>(task_type)); | |||
| const domi::KernelDef &kernel_def = task_def.kernel(); | |||
| AiCoreOpTask *aicore_op_task = nullptr; | |||
| // not use hybrid model now | |||
| GE_CHK_STATUS_RET_NOLOG(BuildAiCoreTask(kernel_def, node->GetOpDesc(), &aicore_op_task)); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aicore_op_task == nullptr, return FAILED, "BuildAiCoreTask[%s] failed.", | |||
| node->GetName().c_str()); | |||
| aicore_op_tasks.emplace_back(std::unique_ptr<AiCoreOpTask>(aicore_op_task)); | |||
| } | |||
| GELOGI("AiCoreNodeExecutor(%s) CompileTask End.", node->GetName().c_str()); | |||
| if (!aicore_op_tasks.empty()) { | |||
| auto aic_task = std::shared_ptr<NodeTask>(new AiCoreNodeTask(std::move(aicore_op_tasks))); | |||
| task = std::move(aic_task); | |||
| GELOGD("Generate AiCoreOpTask success"); | |||
| return SUCCESS; | |||
| } | |||
| GELOGE(INTERNAL_ERROR, "Failed to build task. node = %s", node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| Status AiCoreNodeExecutor::Initialize() { | |||
| std::shared_ptr<GELib> ge_lib = GELib::GetInstance(); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG((ge_lib == nullptr) || !ge_lib->InitFlag(), return GE_CLI_GE_NOT_INITIALIZED, | |||
| "Get ge_lib failed."); | |||
| auto &kernel_manager = ge_lib->OpsKernelManagerObj(); | |||
| auto aic_ops_store = kernel_manager.GetOpsKernelInfoStore("AIcoreEngine"); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aic_ops_store == nullptr, return GE_CLI_GE_NOT_INITIALIZED, | |||
| "Failed to get kernel info store for AIcoreEngine."); | |||
| compiler_.reset(new (std::nothrow) AiCoreTaskCompiler(aic_ops_store)); | |||
| GE_CHECK_NOTNULL(compiler_); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeExecutor::Finalize() { return NodeExecutor::Finalize(); } | |||
| Status AiCoreNodeTask::ExecuteAsync(TaskContext &context, std::function<void()> done_callback) { | |||
| auto op_desc = context.GetNodeItem().op_desc; | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| GELOGI("[%s] ExecuteAsync Start.", op_desc->GetName().c_str()); | |||
| for (auto &task : tasks_) { | |||
| GE_CHK_STATUS_RET_NOLOG(task->LaunchKernel(context.GetStream())); | |||
| GELOGI("AiCoreNodeTask[%s] ExecuteAsync Start.", op_desc->GetName().c_str()); | |||
| for (size_t i = 0; i < tasks_.size(); i++) { | |||
| GE_CHECK_NOTNULL(tasks_[i]); | |||
| GE_CHK_STATUS_RET_NOLOG(tasks_[i]->LaunchKernel(context.GetStream())); | |||
| } | |||
| if (done_callback != nullptr) { | |||
| GE_CHK_STATUS_RET_NOLOG(context.RegisterCallback(done_callback)); | |||
| } | |||
| GELOGD("[%s] ExecuteAsync End.", op_desc->GetName().c_str()); | |||
| GELOGI("AiCoreNodeTask[%s] ExecuteAsync End.", op_desc->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeTask::UpdateArgs(TaskContext &context) { | |||
| Status AiCoreNodeTask::UpdateAtomicArgs(TaskContext &context, std::unique_ptr<AiCoreOpTask> &task) { | |||
| GE_CHECK_NOTNULL(task); | |||
| auto op_desc = context.GetNodeItem().op_desc; | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| GELOGI("[%s] AiCoreNodeTask UpdateArgs Start.", op_desc->GetName().c_str()); | |||
| for (auto &task : tasks_) { | |||
| GE_CHK_STATUS_RET_NOLOG(task->UpdateArgs(context)); | |||
| // refresh atomic output addr | |||
| std::vector<int64_t> atomic_output_indexes; // here atomic just clean output | |||
| (void)ge::AttrUtils::GetListInt(op_desc, ge::ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indexes); | |||
| GE_RETURN_WITH_LOG_IF_TRUE(atomic_output_indexes.size() > static_cast<size_t>(context.NumOutputs()), | |||
| "AtomicAddrClean op's arg_size error."); | |||
| auto *arg_off = reinterpret_cast<uint8_t *>(task->args_.get()) + task->offset_; | |||
| auto *arg_base = reinterpret_cast<uintptr_t *>(arg_off); | |||
| int index = 0; | |||
| for (size_t i = 0; i < atomic_output_indexes.size(); ++i) { | |||
| const auto output = context.GetOutput(atomic_output_indexes[i]); | |||
| GE_CHECK_NOTNULL(output); | |||
| arg_base[index++] = reinterpret_cast<uintptr_t>(output->GetData()); | |||
| } | |||
| // refresh atomic workspace addr | |||
| auto workspace_sizes = op_desc->GetWorkspaceBytes(); | |||
| uint64_t ops_workspace_num = static_cast<uint64_t>(workspace_sizes.size()); | |||
| uint64_t workspace_num = static_cast<uint64_t>(context.NumWorkspaces()); | |||
| GE_CHK_BOOL_EXEC(ops_workspace_num == workspace_num, return PARAM_INVALID, | |||
| "The workspace_num in op_desc %lu is not equal to it %lu in context.", ops_workspace_num, | |||
| workspace_num); | |||
| GE_IF_BOOL_EXEC(workspace_num == 0, return SUCCESS); | |||
| map<string, map<int64_t, int64_t>> workspace_info; | |||
| workspace_info = op_desc->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); | |||
| if (!workspace_info.empty()) { | |||
| bool is_fusion_node = false; | |||
| (void)ge::AttrUtils::GetBool(op_desc, ATOMIC_ATTR_IS_FUSION_NODE, is_fusion_node); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(is_fusion_node, return PARAM_INVALID, | |||
| "Atomic desc[%s] shouldn't be fusion_node in AiCoreNodeTask", | |||
| op_desc->GetName().c_str()); | |||
| for (auto iter = workspace_info.begin(); iter != workspace_info.end(); ++iter) { | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(op_desc->GetName() != iter->first, return PARAM_INVALID, | |||
| "The node name %s and the node name %s in workspace info are inconsistent.", | |||
| op_desc->GetName().c_str(), iter->first.c_str()); | |||
| GE_IF_BOOL_EXEC(iter->second.empty(), continue); | |||
| for (auto &info_iter : iter->second) { | |||
| auto workspace_index = static_cast<uint64_t>(info_iter.first); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(workspace_index >= workspace_num, return PARAM_INVALID, | |||
| "The workspace index %lu is more than the size %lu of workspace vector.", | |||
| workspace_index, workspace_num); | |||
| const auto workspace = context.MutableWorkspace(workspace_index); | |||
| arg_base[index++] = reinterpret_cast<uintptr_t>(workspace); | |||
| } | |||
| } | |||
| } | |||
| GELOGI("[%s] AiCoreNodeTask UpdateArgs End.", op_desc->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreNodeTask::UpdateTilingData(TaskContext &context) { | |||
| GELOGD("[%s] PrepareWithShape started", context.GetNodeName()); | |||
| for (auto &task : tasks_) { | |||
| GE_CHK_STATUS_RET_NOLOG(task->PrepareWithShape(context)); | |||
| Status AiCoreNodeTask::UpdateAllArgs(TaskContext &context, std::unique_ptr<AiCoreOpTask> &task) { | |||
| GE_CHECK_NOTNULL(task); | |||
| auto *arg_off = reinterpret_cast<uint8_t *>(task->args_.get()) + task->offset_; | |||
| auto *arg_base = reinterpret_cast<uintptr_t *>(arg_off); | |||
| int index = 0; | |||
| for (int i = 0; i < context.NumInputs(); ++i) { | |||
| const auto input = context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input); | |||
| arg_base[index++] = reinterpret_cast<uintptr_t>(input->GetData()); | |||
| } | |||
| for (int i = 0; i < context.NumOutputs(); ++i) { | |||
| const auto output = context.GetOutput(i); | |||
| GE_CHECK_NOTNULL(output); | |||
| arg_base[index++] = reinterpret_cast<uintptr_t>(output->GetData()); | |||
| } | |||
| auto op_desc = context.GetNodeItem().op_desc; | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| auto workspace_sizes = op_desc->GetWorkspaceBytes(); | |||
| int ops_workspace_num = static_cast<int>(workspace_sizes.size()); | |||
| int workspace_num = static_cast<int>(context.NumWorkspaces()); | |||
| GE_CHK_BOOL_EXEC(ops_workspace_num == workspace_num, return PARAM_INVALID, | |||
| "The workspace_num in op_desc %lu is not equal to it %lu in context.", ops_workspace_num, | |||
| workspace_num); | |||
| for (int i = 0; i < workspace_num; ++i) { | |||
| const auto workspace = context.MutableWorkspace(i); | |||
| arg_base[index++] = reinterpret_cast<uintptr_t>(workspace); | |||
| } | |||
| GELOGD("[%s] Done PrepareWithShape successfully.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| bool AiCoreNodeTask::IsSupportDynamicShape() { | |||
| for (size_t i = 0; i < tasks_.size(); ++i) { | |||
| if (!tasks_[i]->IsDynamicShapeSupported()) { | |||
| GELOGD("[%s] Task does not support dynamic shape.", tasks_[i]->GetName().c_str()); | |||
| return false; | |||
| } | |||
| } | |||
| Status AiCoreNodeTask::UpdateArgs(TaskContext &context) { | |||
| auto op_desc = context.GetNodeItem().op_desc; | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| GELOGI("AiCoreNodeTask[%s] UpdateArgs Start.", op_desc->GetName().c_str()); | |||
| GE_IF_BOOL_EXEC(tasks_.size() == 1, return UpdateAllArgs(context, tasks_[0])); | |||
| std::vector<int64_t> atomic_output_indexes; // here atomic just clean output | |||
| (void)ge::AttrUtils::GetListInt(op_desc, ge::ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indexes); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(atomic_output_indexes.empty(), return FAILED, "ATOMIC_ATTR_OUTPUT_INDEX is empty."); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(tasks_.size() != 2, return FAILED, "AtomicAddrClean op task num != 2."); | |||
| return true; | |||
| GE_CHK_STATUS_RET_NOLOG(UpdateAtomicArgs(context, tasks_[0])); | |||
| GE_CHK_STATUS_RET_NOLOG(UpdateAllArgs(context, tasks_[1])); | |||
| GELOGI("AiCoreNodeTask[%s] UpdateArgs End.", op_desc->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -25,6 +25,7 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class AiCoreNodeTaskRegistry { | |||
| public: | |||
| ~AiCoreNodeTaskRegistry() = default; | |||
| @@ -46,27 +47,32 @@ class AiCoreNodeTaskRegistry { | |||
| class AiCoreNodeTask : public NodeTask { | |||
| public: | |||
| explicit AiCoreNodeTask(std::vector<std::unique_ptr<AiCoreOpTask>> &&tasks); | |||
| ~AiCoreNodeTask() override = default; | |||
| bool IsSupportDynamicShape() override; | |||
| Status UpdateTilingData(TaskContext &context) override; | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| ~AiCoreNodeTask() = default; | |||
| Status ExecuteAsync(TaskContext &context, std::function<void()> done_callback) override; | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| private: | |||
| static Status UpdateAllArgs(TaskContext &context, std::unique_ptr<AiCoreOpTask> &task); | |||
| static Status UpdateAtomicArgs(TaskContext &context, std::unique_ptr<AiCoreOpTask> &task); | |||
| std::vector<std::unique_ptr<AiCoreOpTask>> tasks_; | |||
| }; | |||
| class AiCoreNodeExecutor : public NodeExecutor { | |||
| public: | |||
| Status Initialize() override; | |||
| Status Finalize() override; | |||
| Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const override; | |||
| Status CompileTask(const HybridModel &model, const NodePtr &node, std::shared_ptr<NodeTask> &task) const override; | |||
| private: | |||
| static Status CreateTask(const HybridModel &model, const std::vector<domi::TaskDef> &task_defs, const NodePtr &node, | |||
| std::shared_ptr<NodeTask> &task); | |||
| static Status BuildAiCoreTask(const domi::KernelDef &kernel_def, const OpDescPtr &op_desc, AiCoreOpTask **task); | |||
| static Status GenNodeKey(const NodePtr &node, std::string &node_key); | |||
| std::unique_ptr<AiCoreTaskCompiler> compiler_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_KERNEL_AICORE_NODE_EXECUTOR_H_ | |||
| @@ -14,305 +14,19 @@ | |||
| * limitations under the License. | |||
| */ | |||
| #include "hybrid/node_executor/aicore/aicore_op_task.h" | |||
| #include "cce/taskdown_common.hpp" | |||
| #include "aicore_op_task.h" | |||
| #include "framework/common/debug/log.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/node_executor/aicore/aicore_task_builder.h" | |||
| using optiling::OpRunInfo; | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| constexpr char const *kAttrSupportDynamicShape = "support_dynamicshape"; | |||
| constexpr char const *kAttrOpParamSize = "op_para_size"; | |||
| constexpr char const *kAttrAtomicOpParamSize = "atomic_op_para_size"; | |||
| } // namespace | |||
| Status AiCoreOpTask::Init(const OpDesc &op_desc, const domi::TaskDef &task_def) { | |||
| GE_CHK_STATUS_RET_NOLOG(InitWithTaskDef(op_desc, task_def)); | |||
| GE_CHK_STATUS_RET_NOLOG(InitTilingInfo(op_desc)); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::InitWithTaskDef(const OpDesc &op_desc, const domi::TaskDef &task_def) { | |||
| GE_CHK_STATUS_RET(ValidateTaskDef(task_def), "[%s] Failed to validate task def: [%s]", op_desc.GetName().c_str(), | |||
| task_def.DebugString().c_str()); | |||
| const domi::KernelDef &kernel_def = task_def.kernel(); | |||
| const domi::KernelContext &context = kernel_def.context(); | |||
| stub_name_ = kernel_def.stub_func(); | |||
| GE_CHK_RT_RET(rtGetFunctionByName(stub_name_.c_str(), &stub_func_)); | |||
| args_size_ = kernel_def.args_size(); | |||
| block_dim_ = kernel_def.block_dim(); | |||
| // malloc args memory | |||
| args_.reset(new (std::nothrow) uint8_t[args_size_]); | |||
| GE_CHECK_NOTNULL(args_); | |||
| errno_t err = memcpy_s(args_.get(), args_size_, kernel_def.args().data(), args_size_); | |||
| if (err != EOK) { | |||
| GELOGE(INTERNAL_ERROR, "AiCoreTask memcpy args failed."); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| if (context.args_offset().size() < sizeof(uint16_t)) { | |||
| GELOGE(INTERNAL_ERROR, "Invalid args_offset, size = %zu.", context.args_offset().size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| const auto *args_offset_buffer = reinterpret_cast<const uint16_t *>(context.args_offset().data()); | |||
| uint32_t offset = *args_offset_buffer; | |||
| if (offset > args_size_) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Arg offset out of range. offset = %u, arg size = %u", GetName().c_str(), offset, | |||
| args_size_); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| arg_base_ = reinterpret_cast<uintptr_t *>(args_.get() + offset); | |||
| max_arg_count_ = (args_size_ - offset) / sizeof(void *); | |||
| GELOGD("[%s] Done setting kernel args successfully. stub_func = %s, block_dim = %d, arg base = %p, arg size = %u", | |||
| op_desc.GetName().c_str(), stub_name_.c_str(), block_dim_, arg_base_, args_size_); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::ValidateTaskDef(const domi::TaskDef &task_def) { | |||
| auto task_type = static_cast<rtModelTaskType_t>(task_def.type()); | |||
| if (task_type != RT_MODEL_TASK_KERNEL) { | |||
| GELOGE(INTERNAL_ERROR, "Invalid task type (%d) in AiCore CreateTask.", static_cast<int>(task_type)); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| const domi::KernelDef &kernel_def = task_def.kernel(); | |||
| const domi::KernelContext &context = kernel_def.context(); | |||
| auto kernel_type = static_cast<cce::ccKernelType>(context.kernel_type()); | |||
| if (kernel_type != cce::ccKernelType::TE) { | |||
| GELOGE(INTERNAL_ERROR, "Invalid kernel type(%d) in AiCore TaskDef.", static_cast<int>(kernel_type)); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::PrepareWithShape(TaskContext &context) { | |||
| if (tiling_buffer_ != nullptr) { | |||
| return UpdateTilingInfo(context); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::UpdateTilingInfo(TaskContext &context) { | |||
| auto node = context.GetNodeItem().node; | |||
| GE_CHECK_NOTNULL(node); | |||
| auto op_desc = node->GetOpDesc(); | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| GELOGD("[%s] Start to update tiling info for task: [%s]", node->GetName().c_str(), stub_name_.c_str()); | |||
| OpRunInfo tiling_info; | |||
| tiling_info.block_dim = -1; // codex: Using uninitialized value | |||
| auto execution_context = context.GetExecutionContext(); | |||
| RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CalcTilingInfo] Start"); | |||
| GE_CHK_STATUS_RET(CalcTilingInfo(node, tiling_info)); | |||
| RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CalcTilingInfo] End"); | |||
| // update op args by tiling info | |||
| block_dim_ = static_cast<uint32_t>(tiling_info.block_dim); | |||
| op_desc->SetWorkspaceBytes(tiling_info.workspaces); | |||
| tiling_data_ = tiling_info.tiling_data.str(); | |||
| if (tiling_data_.empty()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Tiling data is empty.", stub_name_.c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| if (tiling_data_.size() > tiling_buffer_->GetSize()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Tiling data size now (%zu) shouldn't larger than we alloc before (%zu).", | |||
| stub_name_.c_str(), tiling_data_.size(), tiling_buffer_->GetSize()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CopyTilingInfo] Start"); | |||
| GE_CHK_RT_RET(rtMemcpy(tiling_buffer_->GetData(), tiling_buffer_->GetSize(), tiling_data_.c_str(), | |||
| tiling_data_.size(), RT_MEMCPY_HOST_TO_DEVICE)); | |||
| RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CopyTilingInfo] End"); | |||
| GELOGD("[%s] Done updating tiling info for task: [%s]", node->GetName().c_str(), stub_name_.c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::CalcTilingInfo(const NodePtr &node, OpRunInfo &tiling_info) { | |||
| GELOGD("[%s] Start to invoke OpParaCalculate.", node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(OpParaCalculate(*node, tiling_info), "Failed calc tiling data of node %s.", | |||
| node->GetName().c_str()); | |||
| GELOGD("[%s] Done invoking OpParaCalculate successfully.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::UpdateArgs(TaskContext &task_context) { | |||
| size_t expected_arg_count = task_context.NumInputs() + task_context.NumOutputs() + task_context.NumWorkspaces(); | |||
| if (tiling_buffer_ != nullptr) { | |||
| ++expected_arg_count; | |||
| } | |||
| if (expected_arg_count > max_arg_count_) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Invalid arg memory, max arg count = %u, but expect = %zu", GetName().c_str(), | |||
| max_arg_count_, expected_arg_count); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| int index = 0; | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| const auto input = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input); | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(input->GetData()); | |||
| } | |||
| for (int i = 0; i < task_context.NumOutputs(); ++i) { | |||
| const auto output = task_context.GetOutput(i); | |||
| GE_CHECK_NOTNULL(output); | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(output->GetData()); | |||
| } | |||
| int workspace_num = static_cast<int>(task_context.NumWorkspaces()); | |||
| for (int i = 0; i < workspace_num; ++i) { | |||
| const auto workspace = task_context.MutableWorkspace(i); | |||
| GE_CHECK_NOTNULL(workspace); | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(workspace); | |||
| } | |||
| if (tiling_buffer_ != nullptr) { | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(tiling_buffer_->GetData()); | |||
| } | |||
| if (task_context.IsTraceEnabled()) { | |||
| for (int i = 0; i < index; ++i) { | |||
| GELOGD("[%s] Arg[%d] = %lu", stub_name_.c_str(), i, arg_base_[i]); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::LaunchKernel(rtStream_t stream) { | |||
| GELOGD("AiCoreOpTask LaunchKernel Start (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); | |||
| GE_CHK_RT_RET(rtKernelLaunch(stub_func_, block_dim_, args_.get(), args_size_, nullptr, stream)); | |||
| GELOGD("AiCoreOpTask LaunchKernel End (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); | |||
| return SUCCESS; | |||
| } | |||
| Status AiCoreOpTask::InitTilingInfo(const OpDesc &op_desc) { | |||
| bool dynamic_supported = false; | |||
| (void)AttrUtils::GetBool(op_desc, kAttrSupportDynamicShape, dynamic_supported); | |||
| if (!dynamic_supported) { | |||
| GELOGD("[%s] Dynamic shape is not supported.", op_desc.GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| GELOGD("Start alloc tiling data of node %s.", op_desc.GetName().c_str()); | |||
| int64_t max_size = -1; | |||
| (void)AttrUtils::GetInt(op_desc, GetKeyForOpParamSize(), max_size); | |||
| GELOGD("Got op param size by key: %s, ret = %ld", GetKeyForOpParamSize().c_str(), max_size); | |||
| if (max_size <= 0) { | |||
| GELOGE(PARAM_INVALID, "[%s] Invalid op_param_size: %ld.", op_desc.GetName().c_str(), max_size); | |||
| return PARAM_INVALID; | |||
| } | |||
| auto allocator = NpuMemoryAllocator::GetAllocator(); | |||
| GE_CHECK_NOTNULL(allocator); | |||
| tiling_buffer_ = TensorBuffer::Create(allocator, static_cast<size_t>(max_size)); | |||
| GE_CHECK_NOTNULL(tiling_buffer_); | |||
| GELOGD("[%s] Done allocating tiling buffer, size=%ld.", op_desc.GetName().c_str(), max_size); | |||
| return SUCCESS; | |||
| } | |||
| bool AiCoreOpTask::IsDynamicShapeSupported() { return tiling_buffer_ != nullptr; } | |||
| const std::string &AiCoreOpTask::GetName() const { return stub_name_; } | |||
| std::string AiCoreOpTask::GetKeyForOpParamSize() const { return kAttrOpParamSize; } | |||
| Status AtomicAddrCleanOpTask::Init(const OpDesc &op_desc, const domi::TaskDef &task_def) { | |||
| GE_CHK_STATUS_RET_NOLOG(AiCoreOpTask::Init(op_desc, task_def)); | |||
| return InitAtomicAddrCleanIndices(op_desc); | |||
| } | |||
| Status AtomicAddrCleanOpTask::InitAtomicAddrCleanIndices(const OpDesc &op_desc) { | |||
| GELOGD("[%s] Start to setup AtomicAddrClean task.", op_desc.GetName().c_str()); | |||
| std::vector<int64_t> atomic_output_indices; | |||
| (void)ge::AttrUtils::GetListInt(op_desc, ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indices); | |||
| map<string, map<int64_t, int64_t>> workspace_info; // op_name, ws_index, ws_offset | |||
| workspace_info = op_desc.TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); | |||
| if (atomic_output_indices.empty() && workspace_info.empty()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Neither ATOMIC_ATTR_OUTPUT_INDEX nor EXT_ATTR_ATOMIC_WORKSPACE_INFO is empty.", | |||
| op_desc.GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| for (auto output_index : atomic_output_indices) { | |||
| GELOGD("[%s] Adding output index [%ld]", op_desc.GetName().c_str(), output_index); | |||
| GE_CHECK_GE(output_index, 0); | |||
| GE_CHECK_LE(output_index, INT32_MAX); | |||
| atomic_output_indices_.emplace_back(static_cast<int>(output_index)); | |||
| } | |||
| for (auto &iter : workspace_info) { | |||
| for (auto &info_iter : iter.second) { | |||
| auto workspace_index = info_iter.first; | |||
| GELOGD("[%s] Adding workspace index [%ld]", op_desc.GetName().c_str(), workspace_index); | |||
| GE_CHECK_GE(workspace_index, 0); | |||
| GE_CHECK_LE(workspace_index, INT32_MAX); | |||
| atomic_workspace_indices_.emplace_back(static_cast<int>(workspace_index)); | |||
| } | |||
| } | |||
| size_t arg_count = atomic_workspace_indices_.size() + atomic_output_indices_.size(); | |||
| if (tiling_buffer_ != nullptr) { | |||
| arg_count += 1; | |||
| } | |||
| if (arg_count > max_arg_count_) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Invalid arg memory, max arg count = %u, but expect = %zu", GetName().c_str(), | |||
| max_arg_count_, arg_count); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGI("AiCoreOpTask LaunchKernel Start (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); | |||
| GE_CHK_RT_RET(rtKernelLaunch(stub_func_, block_dim_, args_.get(), args_size_, nullptr, stream)); | |||
| GELOGI("AiCoreOpTask LaunchKernel End (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); | |||
| return SUCCESS; | |||
| } | |||
| std::string AtomicAddrCleanOpTask::GetKeyForOpParamSize() const { return kAttrAtomicOpParamSize; } | |||
| Status AtomicAddrCleanOpTask::UpdateArgs(TaskContext &task_context) { | |||
| // refresh atomic output addr | |||
| int index = 0; | |||
| for (auto atomic_output_index : atomic_output_indices_) { | |||
| const auto output_tensor = task_context.GetOutput(atomic_output_index); | |||
| GE_CHECK_NOTNULL(output_tensor); | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(output_tensor->GetData()); | |||
| } | |||
| // refresh atomic workspace addr | |||
| for (auto atomic_ws_index : atomic_workspace_indices_) { | |||
| const auto workspace_tensor = task_context.GetOutput(atomic_ws_index); | |||
| GE_CHECK_NOTNULL(workspace_tensor); | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(workspace_tensor->GetData()); | |||
| } | |||
| if (tiling_buffer_ != nullptr) { | |||
| arg_base_[index++] = reinterpret_cast<uintptr_t>(tiling_buffer_->GetData()); | |||
| } else { | |||
| GELOGD("[%s] Not a dynamic op", GetName().c_str()); | |||
| } | |||
| if (task_context.IsTraceEnabled()) { | |||
| for (int i = 0; i < index; ++i) { | |||
| GELOGD("[%s] Arg[%d] = %lu", GetName().c_str(), i, arg_base_[i]); | |||
| } | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| } // namespace ge | |||
| @@ -18,69 +18,27 @@ | |||
| #define GE_HYBRID_KERNEL_AICORE_OP_TASK_H_ | |||
| #include <memory> | |||
| #include <vector> | |||
| #include "common/ge_inner_error_codes.h" | |||
| #include "runtime/stream.h" | |||
| #include "hybrid/common/tensor_value.h" | |||
| #include "hybrid/node_executor/task_context.h" | |||
| #include "proto/task.pb.h" | |||
| #include "register/op_tiling.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class AiCoreOpTask { | |||
| public: | |||
| AiCoreOpTask() = default; | |||
| virtual ~AiCoreOpTask() = default; | |||
| virtual Status Init(const OpDesc &op_desc, const domi::TaskDef &task_def); | |||
| bool IsDynamicShapeSupported(); | |||
| // do preparation with shape(without actual io memory) | |||
| Status PrepareWithShape(TaskContext &context); | |||
| virtual Status UpdateArgs(TaskContext &task_context); | |||
| ~AiCoreOpTask() = default; | |||
| Status LaunchKernel(rtStream_t stream); | |||
| const std::string &GetName() const; | |||
| protected: | |||
| Status UpdateTilingInfo(TaskContext &context); | |||
| virtual std::string GetKeyForOpParamSize() const; | |||
| virtual Status CalcTilingInfo(const NodePtr &node, optiling::OpRunInfo &tiling_info); | |||
| std::unique_ptr<TensorBuffer> tiling_buffer_ = nullptr; | |||
| std::string tiling_data_; | |||
| uintptr_t *arg_base_ = nullptr; | |||
| uint32_t max_arg_count_ = 0; | |||
| private: | |||
| static Status ValidateTaskDef(const domi::TaskDef &task_def); | |||
| Status InitWithTaskDef(const OpDesc &node, const domi::TaskDef &task_def); | |||
| Status InitTilingInfo(const OpDesc &op_desc); | |||
| friend class AiCoreTaskBuilder; | |||
| friend class AiCoreNodeTask; | |||
| std::string stub_name_; | |||
| void *stub_func_ = nullptr; | |||
| std::unique_ptr<uint8_t[]> args_ = nullptr; | |||
| uint32_t args_size_ = 0; | |||
| uint32_t block_dim_ = 1; | |||
| uint16_t offset_ = 0; | |||
| }; | |||
| class AtomicAddrCleanOpTask : public AiCoreOpTask { | |||
| public: | |||
| Status Init(const OpDesc &op_desc, const domi::TaskDef &task_def) override; | |||
| Status UpdateArgs(TaskContext &task_context) override; | |||
| protected: | |||
| std::string GetKeyForOpParamSize() const override; | |||
| private: | |||
| Status InitAtomicAddrCleanIndices(const OpDesc &op_desc); | |||
| std::vector<int> atomic_output_indices_; | |||
| std::vector<int> atomic_workspace_indices_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_KERNEL_AICORE_OP_TASK_H_ | |||
| @@ -15,78 +15,76 @@ | |||
| */ | |||
| #include "aicore_task_builder.h" | |||
| #include "common/debug/log.h" | |||
| #include "aicore_node_executor.h" | |||
| #include <mutex> | |||
| #include "graph/op_desc.h" | |||
| #include "cce/taskdown_common.hpp" | |||
| #include "framework/common/debug/log.h" | |||
| #include "graph/debug/ge_attr_define.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| namespace { | |||
| const size_t kNumTaskWithAtomicAddrCleanTask = 2; | |||
| std::mutex g_reg_mutex; | |||
| AiCoreTaskBuilder::AiCoreTaskBuilder(const OpDescPtr &op_desc, const domi::KernelDef &kernel_def) | |||
| : op_desc_(op_desc), kernel_def_(kernel_def) { | |||
| std::string session_graph_id; | |||
| GE_IF_BOOL_EXEC(AttrUtils::GetStr(*op_desc_, ATTR_NAME_SESSION_GRAPH_ID, session_graph_id), | |||
| GELOGD("Get original type of session_graph_id.")); | |||
| // get bin_file_key | |||
| stub_name_ = (session_graph_id.empty()) ? op_desc_->GetName() : session_graph_id + "_" + op_desc_->GetName(); | |||
| } | |||
| Status AiCoreTaskBuilder::SetKernelArgs(AiCoreOpTask &task) { | |||
| const domi::KernelContext &context = kernel_def_.context(); | |||
| // get kernel_type | |||
| auto kernel_type = static_cast<cce::ccKernelType>(context.kernel_type()); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(kernel_type != cce::ccKernelType::TE, return UNSUPPORTED, | |||
| "Invalid kernel type[%d] in AiCore TaskDef.", static_cast<int>(kernel_type)); | |||
| task.args_size_ = kernel_def_.args_size(); | |||
| task.block_dim_ = kernel_def_.block_dim(); | |||
| // malloc args memory | |||
| task.args_.reset(new (std::nothrow) uint8_t[task.args_size_]); | |||
| // task.args_ = std::make_unique<uint8_t>(task.args_size_); | |||
| GE_CHECK_NOTNULL(task.args_); | |||
| errno_t err = memcpy_s(task.args_.get(), task.args_size_, kernel_def_.args().data(), task.args_size_); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(err != EOK, return INTERNAL_ERROR, "AiCoreTask memcpy failed."); | |||
| const auto *args_offset_tmp = reinterpret_cast<uint16_t *>(const_cast<char *>(context.args_offset().data())); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(context.args_offset().size() / sizeof(uint16_t) < 1, return FAILED, | |||
| "context.args_offset().size() / sizeof(uint16_t) less than 1"); | |||
| task.offset_ = *args_offset_tmp; | |||
| return SUCCESS; | |||
| } | |||
| const char *AiCoreKernelRegistry::GetUnique(const string &stub_key) { | |||
| std::lock_guard<std::mutex> lock(mutex_); | |||
| auto it = unique_stubs_.find(stub_key); | |||
| if (it != unique_stubs_.end()) { | |||
| return it->c_str(); | |||
| } | |||
| GE_IF_BOOL_EXEC(it != unique_stubs_.end(), return it->c_str()); | |||
| it = unique_stubs_.insert(unique_stubs_.end(), stub_key); | |||
| return it->c_str(); | |||
| } | |||
| AiCoreTaskBuilder::AiCoreTaskBuilder(const OpDescPtr &op_desc, const std::vector<domi::TaskDef> &task_defs) | |||
| : op_desc_(op_desc), task_defs_(task_defs) {} | |||
| Status AiCoreTaskBuilder::SetStub(AiCoreOpTask &task) { | |||
| AiCoreKernelRegistry ®istry = AiCoreKernelRegistry::GetInstance(); | |||
| std::lock_guard<std::mutex> lock(g_reg_mutex); | |||
| const char *unique_key = registry.GetUnique(stub_name_); | |||
| Status AiCoreTaskBuilder::BuildTask(std::unique_ptr<NodeTask> &node_task, bool ignore_failure_on_atomic) { | |||
| GE_CHECK_NOTNULL(op_desc_); | |||
| if (task_defs_.size() > kNumTaskWithAtomicAddrCleanTask) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] At most 2 task was supported, but got %zu", op_desc_->GetName().c_str(), | |||
| task_defs_.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| std::vector<std::unique_ptr<AiCoreOpTask>> op_tasks; | |||
| if (ExpectAtomicAddrCleanTask()) { | |||
| if (task_defs_.size() != kNumTaskWithAtomicAddrCleanTask) { | |||
| if (ignore_failure_on_atomic) { | |||
| GELOGI("[%s] AtomicAddrClean task was expected, but got %zu task_defs", op_desc_->GetName().c_str(), | |||
| task_defs_.size()); | |||
| return SUCCESS; | |||
| } else { | |||
| GELOGE(INTERNAL_ERROR, "[%s] AtomicAddrClean task was expected, but got %zu task_defs", | |||
| op_desc_->GetName().c_str(), task_defs_.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| } | |||
| GELOGD("[%s] Build AtomicAddrClean task.", op_desc_->GetName().c_str()); | |||
| auto atomic_task = std::unique_ptr<AtomicAddrCleanOpTask>(new (std::nothrow) AtomicAddrCleanOpTask()); | |||
| GE_CHECK_NOTNULL(atomic_task); | |||
| GE_CHK_STATUS_RET(atomic_task->Init(*op_desc_, task_defs_.front()), "[%s] Failed to init task for AtomicAddrClean", | |||
| op_desc_->GetName().c_str()); | |||
| op_tasks.emplace_back(std::move(atomic_task)); | |||
| } | |||
| // build aicore task | |||
| auto aicore_task = std::unique_ptr<AiCoreOpTask>(new (std::nothrow) AiCoreOpTask()); | |||
| GE_CHECK_NOTNULL(aicore_task); | |||
| GE_CHK_STATUS_RET(aicore_task->Init(*op_desc_, task_defs_.back()), "[%s] Failed to init task for AtomicAddrClean", | |||
| op_desc_->GetName().c_str()); | |||
| op_tasks.emplace_back(std::move(aicore_task)); | |||
| GE_CHK_RT_RET(rtGetFunctionByName(unique_key, &(task.stub_func_))); | |||
| task.stub_name_ = stub_name_; | |||
| node_task.reset(new (std::nothrow) AiCoreNodeTask(std::move(op_tasks))); | |||
| GE_CHECK_NOTNULL(node_task); | |||
| return SUCCESS; | |||
| } | |||
| bool AiCoreTaskBuilder::ExpectAtomicAddrCleanTask() { | |||
| if (op_desc_->HasAttr(ATOMIC_ATTR_OUTPUT_INDEX)) { | |||
| GELOGD("[%s] Node has ATOMIC_ATTR_OUTPUT_INDEX", op_desc_->GetName().c_str()); | |||
| return true; | |||
| } | |||
| map<string, map<int64_t, int64_t>> workspace_info; | |||
| workspace_info = op_desc_->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); | |||
| return !workspace_info.empty(); | |||
| Status AiCoreTaskBuilder::BuildTask(AiCoreOpTask &task) { | |||
| GE_CHECK_NOTNULL(op_desc_); | |||
| GELOGI("AiCoreTaskBuilder[%s] BuildTask Start.", op_desc_->GetName().c_str()); | |||
| GE_CHK_STATUS_RET_NOLOG(SetKernelArgs(task)); | |||
| GE_CHK_STATUS_RET_NOLOG(SetStub(task)); | |||
| GELOGI("AiCoreTaskBuilder[%s] BuildTask End.", op_desc_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -17,13 +17,14 @@ | |||
| #ifndef GE_HYBRID_KERNEL_AICORE_TASK_BUILDER_H_ | |||
| #define GE_HYBRID_KERNEL_AICORE_TASK_BUILDER_H_ | |||
| #include <vector> | |||
| #include <mutex> | |||
| #include <string> | |||
| #include <map> | |||
| #include <set> | |||
| #include "aicore_op_task.h" | |||
| #include "framework/common/debug/ge_log.h" | |||
| #include "proto/task.pb.h" | |||
| #include "graph/utils/attr_utils.h" | |||
| #include "graph/op_kernel_bin.h" | |||
| #include "proto/task.pb.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| @@ -44,16 +45,16 @@ class AiCoreKernelRegistry { | |||
| class AiCoreTaskBuilder { | |||
| public: | |||
| AiCoreTaskBuilder(const OpDescPtr &op_desc, const std::vector<domi::TaskDef> &task_defs); | |||
| AiCoreTaskBuilder(const OpDescPtr &op_desc, const domi::KernelDef &kernel_def); | |||
| ~AiCoreTaskBuilder() = default; | |||
| Status BuildTask(std::unique_ptr<NodeTask> &node_task, bool ignore_failure_on_atomic); | |||
| Status BuildTask(AiCoreOpTask &task); | |||
| private: | |||
| bool ExpectAtomicAddrCleanTask(); | |||
| OpDescPtr op_desc_; | |||
| const std::vector<domi::TaskDef> &task_defs_; | |||
| Status SetKernelArgs(AiCoreOpTask &task); | |||
| Status SetStub(AiCoreOpTask &task); | |||
| const OpDescPtr &op_desc_; | |||
| const domi::KernelDef &kernel_def_; | |||
| std::string stub_name_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -34,6 +34,7 @@ Status AiCoreTaskCompiler::DoCompileOp(OpsKernelInfoStore &ops_store, const Node | |||
| GE_CHECK_NOTNULL(node); | |||
| vector<NodePtr> node_vec; | |||
| node_vec.emplace_back(node); | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| GE_CHK_STATUS_RET(ops_store.CompileOpRun(node_vec), "Failed to execute CompileOp, node = %s", | |||
| node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET(ops_store.CalcOpRunningParam(*node), "Failed to execute CalcOpRunningParam, node = %s", | |||
| @@ -43,8 +44,9 @@ Status AiCoreTaskCompiler::DoCompileOp(OpsKernelInfoStore &ops_store, const Node | |||
| Status AiCoreTaskCompiler::CompileOp(const NodePtr &node, std::vector<domi::TaskDef> &tasks) const { | |||
| GE_CHECK_NOTNULL(node); | |||
| GELOGI("AiCoreTaskCompiler(%s) CompileOp Start.", node->GetName().c_str()); | |||
| GE_CHECK_NOTNULL(aic_kernel_store_); | |||
| GELOGI("AiCoreTaskCompiler[%s] CompileOp Start.", node->GetName().c_str()); | |||
| GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aic_kernel_store_ == nullptr, return FAILED, | |||
| "Failed to get AiCore kernel store, node = %s", node->GetName().c_str()); | |||
| GE_CHK_STATUS_RET_NOLOG(DoCompileOp(*aic_kernel_store_, node)); | |||
| GELOGD("successfully compiled op: %s", node->GetName().c_str()); | |||
| @@ -56,7 +58,7 @@ Status AiCoreTaskCompiler::CompileOp(const NodePtr &node, std::vector<domi::Task | |||
| op_desc->SetOutputOffset(output_offsets); | |||
| GE_CHK_STATUS_RET_NOLOG(DoGenerateTask(*aic_kernel_store_, *node, tasks)); | |||
| GELOGD("successfully generated task: %s", node->GetName().c_str()); | |||
| GELOGI("AiCoreTaskCompiler(%s) CompileOp End.", node->GetName().c_str()); | |||
| GELOGI("AiCoreTaskCompiler[%s] CompileOp End.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| @@ -89,5 +91,6 @@ Status AiCoreTaskCompiler::DoGenerateTask(OpsKernelInfoStore &store, const Node | |||
| GE_CHK_RT(rtModelDestroy(rt_model_)); | |||
| return ret; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| } // namespace ge | |||
| @@ -199,5 +199,6 @@ void AicpuExtInfoHandler::GetShapeAndType(const AicpuShapeAndType *shape_and_typ | |||
| data_type = static_cast<DataType>(shape_and_type->type); | |||
| shape = std::move(GeShape(dims)); | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -24,6 +24,7 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| using AicpuShapeAndType = aicpu::FWKAdapter::ShapeAndType; | |||
| using AicpuExtInfo = aicpu::FWKAdapter::ExtInfo; | |||
| @@ -40,28 +40,19 @@ Status AicpuNodeTaskBase::AllocTensorBuffer(size_t size, std::unique_ptr<TensorB | |||
| } | |||
| Status AicpuNodeTaskBase::InitExtInfo(const std::string &kernel_ext_info) { | |||
| if (node_item_->is_dynamic) { | |||
| // dynamic node must have ext info | |||
| GE_CHK_STATUS_RET(aicpu_ext_handle_.Parse(kernel_ext_info), | |||
| "Node[%s] parse kernel ext info failed, kernel_ext_info_size=%zu.", node_name_.c_str(), | |||
| kernel_ext_info.size()); | |||
| } | |||
| // if no ext info no need copy to device. | |||
| if (kernel_ext_info.empty()) { | |||
| GELOGI("Node[%s] kernel_ext_info is empty, no need copy to device, is_dynamic=%s.", node_name_.c_str(), | |||
| node_item_->is_dynamic ? "true" : "false"); | |||
| return SUCCESS; | |||
| } | |||
| GE_CHK_STATUS_RET(aicpu_ext_handle_.Parse(kernel_ext_info), | |||
| "Node[%s] parse kernel ext info failed, kernel_ext_info_size=%zu.", node_name_.c_str(), | |||
| kernel_ext_info.size()); | |||
| // copy task args buf | |||
| GE_CHK_STATUS_RET(AllocTensorBuffer(kernel_ext_info.size(), ext_info_addr_dev_), | |||
| "Node[%s] alloc kernel_ext_info buf failed, size=%zu", node_name_.c_str(), kernel_ext_info.size()); | |||
| // copy default ext info to device | |||
| GE_CHK_RT_RET(rtMemcpy(ext_info_addr_dev_->GetData(), ext_info_addr_dev_->GetSize(), kernel_ext_info.data(), | |||
| kernel_ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE)); | |||
| // if no input and no output(DEPEND_COMPUTE equal no output), copy once, or else copy when update args. | |||
| if (node_item_->num_inputs == 0 && ((unknown_type_ == DEPEND_COMPUTE) || (node_item_->num_outputs == 0))) { | |||
| GE_CHK_RT_RET(rtMemcpy(ext_info_addr_dev_->GetData(), ext_info_addr_dev_->GetSize(), kernel_ext_info.data(), | |||
| kernel_ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE)); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| @@ -148,18 +139,16 @@ Status AicpuNodeTaskBase::UpdateExtInfo() { | |||
| } | |||
| Status AicpuNodeTaskBase::UpdateArgs(TaskContext &context) { | |||
| GELOGI("Node[%s] update args begin. is_dynamic=%s, unknown_type=%d", node_name_.c_str(), | |||
| node_item_->is_dynamic ? "true" : "false", unknown_type_); | |||
| GELOGI("Node[%s] update args begin. unknown_type=%d", node_name_.c_str(), unknown_type_); | |||
| if (node_item_->num_inputs == 0 && node_item_->num_outputs == 0) { | |||
| GELOGI("Node[%s] has no input and output, no need update args.", node_name_.c_str()); | |||
| return SUCCESS; | |||
| } | |||
| GE_CHK_STATUS_RET(UpdateIoAddr(context), "Node[%s] update io addr failed.", node_name_.c_str()); | |||
| if (node_item_->is_dynamic) { | |||
| // dynamic node need update ext info. | |||
| GE_CHK_STATUS_RET(UpdateExtInfo(), "Node[%s] update ext info failed.", node_name_.c_str()); | |||
| } | |||
| GE_CHK_STATUS_RET(UpdateExtInfo(), "Node[%s] update ext info failed.", node_name_.c_str()); | |||
| GELOGI("Node[%s] update args end.", node_name_.c_str()); | |||
| return SUCCESS; | |||
| } | |||
| @@ -286,12 +275,9 @@ Status AicpuTfNodeTask::Init(const HybridModel &model) { | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.workspaceBaseAddr = reinterpret_cast<uintptr_t>(kernel_workspace_->GetData()); | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.inputOutputAddr = reinterpret_cast<uintptr_t>(input_output_addr_->GetData()); | |||
| if (ext_info_addr_dev_ != nullptr) { | |||
| // set ext info addr and ext info num | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast<uintptr_t>(ext_info_addr_dev_->GetData()); | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoLen = ext_info_addr_dev_->GetSize(); | |||
| } | |||
| // set ext info addr and ext info num | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast<uintptr_t>(ext_info_addr_dev_->GetData()); | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoLen = ext_info_addr_dev_->GetSize(); | |||
| fwk_op_kernel.fwkKernelBase.fwk_kernel.stepIDAddr = GetStepIdAddr(model); | |||
| @@ -520,8 +506,7 @@ Status AicpuTfNodeTask::UpdateIoAddr(TaskContext &context) { | |||
| io_addrs.emplace_back(reinterpret_cast<uintptr_t>(inputData->GetData())); | |||
| } | |||
| // known shape or not depend compute | |||
| if (!node_item_->is_dynamic || unknown_type_ != DEPEND_COMPUTE) { | |||
| if (unknown_type_ != DEPEND_COMPUTE) { | |||
| // unknown type 4 do this in call back. | |||
| GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); | |||
| for (auto j = 0; j < node_item_->num_outputs; ++j) { | |||
| @@ -563,17 +548,14 @@ Status AicpuTfNodeTask::LaunchTask(TaskContext &context) { | |||
| } | |||
| Status AicpuTfNodeTask::TaskCallback(TaskContext &context) { | |||
| GELOGI("Node[%s] task callback start. is_dynamic=%s, unknown_type=%d.", node_name_.c_str(), | |||
| node_item_->is_dynamic ? "true" : "false", unknown_type_); | |||
| GELOGI("Node[%s] task callback start. unknown_type=%d.", node_name_.c_str(), unknown_type_); | |||
| Status callback_ret = SUCCESS; | |||
| if (node_item_->is_dynamic) { | |||
| // check need update shape, call update shape. | |||
| if (unknown_type_ == DEPEND_SHAPE_RANGE) { | |||
| // check result | |||
| callback_ret = UpdateOutputShapeFromExtInfo(); | |||
| } else if (unknown_type_ == DEPEND_COMPUTE) { | |||
| callback_ret = UpdateShapeAndDataByResultSummary(context); | |||
| } | |||
| // check need update shape, call update shape. | |||
| if (unknown_type_ == DEPEND_SHAPE_RANGE) { | |||
| // check result | |||
| callback_ret = UpdateOutputShapeFromExtInfo(); | |||
| } else if (unknown_type_ == DEPEND_COMPUTE) { | |||
| callback_ret = UpdateShapeAndDataByResultSummary(context); | |||
| } | |||
| GELOGI("Node[%s] task callback end.", node_name_.c_str()); | |||
| return callback_ret; | |||
| @@ -630,13 +612,8 @@ Status AicpuNodeTask::Init(const HybridModel &model) { | |||
| GE_CHK_STATUS_RET(InitExtInfo(kernel_ext_info), "Node[%s] init ext info failed.", node_name.c_str()); | |||
| if (ext_info_addr_dev_ == nullptr) { | |||
| aicpu_param_head->extInfoLength = 0; | |||
| aicpu_param_head->extInfoAddr = 0; | |||
| } else { | |||
| aicpu_param_head->extInfoLength = ext_info_addr_dev_->GetSize(); | |||
| aicpu_param_head->extInfoAddr = reinterpret_cast<uintptr_t>(ext_info_addr_dev_->GetData()); | |||
| } | |||
| aicpu_param_head->extInfoLength = ext_info_addr_dev_->GetSize(); | |||
| aicpu_param_head->extInfoAddr = reinterpret_cast<uintptr_t>(ext_info_addr_dev_->GetData()); | |||
| GELOGI("Node[%s] init end.", node_name.c_str()); | |||
| return SUCCESS; | |||
| @@ -687,12 +664,10 @@ Status AicpuNodeTask::LaunchTask(TaskContext &context) { | |||
| } | |||
| Status AicpuNodeTask::TaskCallback(TaskContext &context) { | |||
| GELOGI("Node[%s] task callback start, is_dynamic = %s, unknown_type=%d.", node_name_.c_str(), | |||
| node_item_->is_dynamic ? "true" : "false", unknown_type_); | |||
| GELOGI("Node[%s] task callback start, unknown_type=%d.", node_name_.c_str(), unknown_type_); | |||
| Status callback_ret = SUCCESS; | |||
| // check need update shape, call update shape. | |||
| if (node_item_->is_dynamic && unknown_type_ == DEPEND_SHAPE_RANGE) { | |||
| if (unknown_type_ == DEPEND_SHAPE_RANGE) { | |||
| // check result | |||
| callback_ret = UpdateOutputShapeFromExtInfo(); | |||
| } else { | |||
| @@ -24,6 +24,7 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class AicpuNodeTaskBase : public NodeTask { | |||
| public: | |||
| AicpuNodeTaskBase(const NodeItem *node_item, const domi::TaskDef &task_def) | |||
| @@ -69,10 +70,8 @@ class AicpuNodeTaskBase : public NodeTask { | |||
| const std::string node_type_; | |||
| // valid when node_item_->is_dynamic is true | |||
| UnknowShapeOpType unknown_type_ = DEPEND_IN_SHAPE; | |||
| // valid when node_item_->is_dynamic is true | |||
| AicpuExtInfoHandler aicpu_ext_handle_; | |||
| // ext info addr, device mem | |||
| @@ -170,6 +169,7 @@ class AiCpuNodeExecutor : public NodeExecutor { | |||
| Status PrepareTask(NodeTask &task, TaskContext &context) const override; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_KERNEL_AICPU_NODE_EXECUTOR_H_ | |||
| @@ -26,6 +26,7 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::COMPILED_SUBGRAPH, KnownNodeExecutor); | |||
| Status KnownNodeTask::ExecuteAsync(TaskContext &context, std::function<void()> done_callback) { | |||
| @@ -97,11 +98,8 @@ Status KnownNodeTask::Init(TaskContext &context) { | |||
| GE_CHK_STATUS_RET(context.AllocateOutputs(), "known node task allocate output failed."); | |||
| // init davinicmodel | |||
| if (!load_flag_) { | |||
| davinci_model_->InitRuntimeParams(); | |||
| GE_CHK_STATUS_RET(davinci_model_->InitVariableMem(), "init variable mem failed."); | |||
| } | |||
| davinci_model_->InitRuntimeParams(); | |||
| GE_CHK_STATUS_RET(davinci_model_->InitVariableMem(), "init variable mem failed."); | |||
| // allocate mem base | |||
| void *buffer = nullptr; | |||
| if (davinci_model_->TotalMemSize() != 0) { | |||
| @@ -163,5 +161,6 @@ Status KnownNodeExecutor::ExecuteTask(NodeTask &task, TaskContext &context, | |||
| context.GetNodeItem().NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,318 +0,0 @@ | |||
| /** | |||
| * 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 "control_op_executor.h" | |||
| #include "graph/utils/node_utils.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/subgraph_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::CONTROL_OP, ControlOpNodeExecutor); | |||
| Status ControlOpNodeTask::ExecuteSubgraph(const GraphItem *subgraph, TaskContext &task_context, | |||
| const std::function<void()> &done_callback) { | |||
| GELOGD("[%s] Start to execute subgraph.", subgraph->GetName().c_str()); | |||
| auto execution_context = const_cast<GraphExecutionContext *>(task_context.GetExecutionContext()); | |||
| auto executor = MakeShared<SubgraphExecutor>(subgraph, execution_context, task_context.IsForceInferShape()); | |||
| GE_CHECK_NOTNULL(executor); | |||
| GE_CHK_STATUS_RET(executor->ExecuteAsync(task_context), "[%s] Failed to execute partitioned call.", | |||
| subgraph->GetName().c_str()); | |||
| auto callback = [executor, done_callback]() mutable { | |||
| if (done_callback != nullptr) { | |||
| done_callback(); | |||
| } | |||
| // executor must outlive task context | |||
| executor.reset(); | |||
| }; | |||
| GE_CHK_STATUS_RET_NOLOG(task_context.RegisterCallback(callback)); | |||
| GELOGD("[%s] Done executing subgraph successfully.", subgraph->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status ControlOpNodeTask::CopyTensorValueToHost(const TensorValue &tensor, int32_t &value) { | |||
| GE_CHECK_NOTNULL(tensor.GetData()); | |||
| GE_CHECK_GE(tensor.GetSize(), sizeof(value)); | |||
| GE_CHK_RT_RET(rtMemcpy(&value, sizeof(value), tensor.GetData(), sizeof(value), RT_MEMCPY_DEVICE_TO_HOST)); | |||
| return SUCCESS; | |||
| } | |||
| Status ControlOpNodeTask::UpdateArgs(TaskContext &context) { | |||
| // do nothing | |||
| return SUCCESS; | |||
| } | |||
| Status ControlOpNodeTask::ExecuteAsync(TaskContext &task_context, std::function<void()> done_callback) { | |||
| auto ret = DoExecuteAsync(task_context, done_callback); | |||
| task_context.SetStatus(ret); | |||
| if (done_callback) { | |||
| done_callback(); | |||
| } | |||
| return ret; | |||
| } | |||
| Status IfOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { | |||
| GELOGD("[%s] Start to init IfOpNodeTask.", node->GetName().c_str()); | |||
| auto then_subgraph = NodeUtils::GetSubgraph(*node, kThenBranchIndex); | |||
| GE_CHECK_NOTNULL(then_subgraph); | |||
| GELOGD("[%s] Adding subgraph [%s] to then-subgraph.", node->GetName().c_str(), then_subgraph->GetName().c_str()); | |||
| then_ = model.GetSubgraphItem(then_subgraph); | |||
| GE_CHECK_NOTNULL(then_); | |||
| auto else_subgraph = NodeUtils::GetSubgraph(*node, kElseBranchIndex); | |||
| GE_CHECK_NOTNULL(else_subgraph); | |||
| GELOGD("[%s] Adding subgraph [%s] to else-subgraph.", node->GetName().c_str(), else_subgraph->GetName().c_str()); | |||
| else_ = model.GetSubgraphItem(else_subgraph); | |||
| GE_CHECK_NOTNULL(else_); | |||
| GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| const GraphItem *IfOpNodeTask::SelectBranch(int32_t cond) const { return cond != 0 ? then_ : else_; } | |||
| Status IfOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const { | |||
| auto cond_tensor = task_context.GetInput(kIfCondIndex); | |||
| GE_CHECK_NOTNULL(cond_tensor); | |||
| int32_t cond_val = 0; | |||
| GE_CHK_STATUS_RET(CopyTensorValueToHost(*cond_tensor, cond_val), "[%s] Failed to get cond value.", | |||
| task_context.GetNodeName()); | |||
| auto subgraph = SelectBranch(cond_val); | |||
| GELOGD("[%s] Taking subgraph [%s] by cond = [%d]", task_context.GetNodeName(), subgraph->GetName().c_str(), cond_val); | |||
| GE_CHK_STATUS_RET(ExecuteSubgraph(subgraph, task_context, done_callback), | |||
| "[%s] Failed to execute subgraph. cond = %d", task_context.GetNodeName(), cond_val); | |||
| GELOGD("[%s] Done executing with cond = %d successfully.", task_context.GetNodeName(), cond_val); | |||
| return SUCCESS; | |||
| } | |||
| Status CaseOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { | |||
| size_t num_subgraphs = node->GetOpDesc()->GetSubgraphInstanceNames().size(); | |||
| GE_CHECK_LE(num_subgraphs, kMaxBranchNum); | |||
| GE_CHECK_GE(num_subgraphs, kMinBranchNum); | |||
| auto num_branches = static_cast<uint32_t>(num_subgraphs); | |||
| GELOGD("[%s] Start to init CaseOpNodeTask with %u branches.", node->GetName().c_str(), num_branches); | |||
| for (uint32_t i = 0; i < num_branches; ++i) { | |||
| auto sub_graph = NodeUtils::GetSubgraph(*node, i); | |||
| GE_CHECK_NOTNULL(sub_graph); | |||
| auto graph_item = model.GetSubgraphItem(sub_graph); | |||
| GE_CHECK_NOTNULL(graph_item); | |||
| GELOGD("[%s] Adding subgraph [%s] to branch %u.", node->GetName().c_str(), sub_graph->GetName().c_str(), i); | |||
| subgraphs_.emplace_back(graph_item); | |||
| } | |||
| GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| const GraphItem *CaseOpNodeTask::SelectBranch(int32_t branch_index) const { | |||
| // subgraphs_ is non-empty. checked int Init | |||
| if (branch_index < 0 || static_cast<size_t>(branch_index) >= subgraphs_.size()) { | |||
| GELOGI("Branch index out of range. index = %d, num_subgraphs = %zu, will taking last branch.", branch_index, | |||
| subgraphs_.size()); | |||
| branch_index = subgraphs_.size() - 1; | |||
| } | |||
| return subgraphs_[branch_index]; | |||
| } | |||
| Status CaseOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const { | |||
| auto branch_tensor = task_context.GetInput(kCaseBranchIndex); | |||
| GE_CHECK_NOTNULL(branch_tensor); | |||
| int32_t branch_index = 0; | |||
| GE_CHK_STATUS_RET(CopyTensorValueToHost(*branch_tensor, branch_index), "[%s] Failed to get branch index.", | |||
| task_context.GetNodeName()); | |||
| const GraphItem *subgraph = SelectBranch(branch_index); | |||
| GELOGI("[%s] Taking subgraph [%s] by branch = [%d]", task_context.GetNodeName(), subgraph->GetName().c_str(), | |||
| branch_index); | |||
| std::vector<TensorValue> inputs; | |||
| std::vector<TensorValue> outputs; | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| auto input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| inputs.emplace_back(*input_tensor); | |||
| } | |||
| GE_CHK_STATUS_RET(ExecuteSubgraph(subgraph, task_context, done_callback), "[%s] Failed to execute else-subgraph.", | |||
| task_context.GetNodeName()); | |||
| GELOGD("[%s] Done executing subgraph[%d] successfully.", task_context.GetNodeName(), branch_index); | |||
| return SUCCESS; | |||
| } | |||
| Status WhileOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { | |||
| GELOGD("[%s] Start to init WhileOpNodeTask.", node->GetName().c_str()); | |||
| auto cond_subgraph = NodeUtils::GetSubgraph(*node, kCondBranchIndex); | |||
| GE_CHECK_NOTNULL(cond_subgraph); | |||
| GELOGD("[%s] Adding subgraph [%s] to cond-subgraph.", node->GetName().c_str(), cond_subgraph->GetName().c_str()); | |||
| cond_ = model.GetSubgraphItem(cond_subgraph); | |||
| GE_CHECK_NOTNULL(cond_); | |||
| auto body_subgraph = NodeUtils::GetSubgraph(*node, kBodyBranchIndex); | |||
| GE_CHECK_NOTNULL(body_subgraph); | |||
| GELOGD("[%s] Adding subgraph [%s] to body-subgraph.", node->GetName().c_str(), body_subgraph->GetName().c_str()); | |||
| body_ = model.GetSubgraphItem(body_subgraph); | |||
| GE_CHECK_NOTNULL(body_); | |||
| GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status WhileOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const { | |||
| if (task_context.NumInputs() != task_context.NumOutputs()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Invalid while args. num_inputs = %d, num_outputs = %d", task_context.GetNodeName(), | |||
| task_context.NumInputs(), task_context.NumOutputs()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| // graph build can not set accurate flag unknown_shape_status by now. | |||
| // Treating all nodes in while scope as unknown shape. | |||
| task_context.SetForceInferShape(true); | |||
| int iteration = 0; | |||
| while (true) { | |||
| bool is_continue = false; | |||
| GELOGD("[%s] Start to execute, iteration = %d", task_context.GetNodeName(), iteration); | |||
| GE_CHK_STATUS_RET(ExecuteOneLoop(task_context, is_continue), "[%s] Failed to execute iteration %d.", | |||
| task_context.GetNodeName(), iteration); | |||
| if (!is_continue) { | |||
| GELOGD("[%s] Quit from loop. current iteration = %d", task_context.GetNodeName(), iteration); | |||
| break; | |||
| } | |||
| ++iteration; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status WhileOpNodeTask::ExecuteCond(TaskContext &task_context, bool &is_continue) const { | |||
| std::vector<TensorValue> inputs; | |||
| std::vector<ConstGeTensorDescPtr> input_desc; | |||
| std::vector<ConstGeTensorDescPtr> output_desc; | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| auto input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| inputs.emplace_back(*input_tensor); | |||
| input_desc.emplace_back(task_context.GetInputDesc(i)); | |||
| } | |||
| auto execution_context = const_cast<GraphExecutionContext *>(task_context.GetExecutionContext()); | |||
| auto executor = MakeShared<SubgraphExecutor>(cond_, execution_context, task_context.IsForceInferShape()); | |||
| GE_CHECK_NOTNULL(executor); | |||
| GELOGD("[%s] Start to execute cond-subgraph.", task_context.GetNodeName()); | |||
| GE_CHK_STATUS_RET(executor->ExecuteAsync(inputs, input_desc), "Failed to execute partitioned call."); | |||
| GELOGD("[%s] Done executing cond-subgraph successfully.", cond_->GetName().c_str()); | |||
| GE_CHK_STATUS_RET_NOLOG(task_context.RegisterCallback([executor]() mutable { executor.reset(); })); | |||
| // get cond output | |||
| GE_CHK_STATUS_RET(executor->Synchronize(), "[%s] Failed to sync cond-subgraph result.", cond_->GetName().c_str()); | |||
| std::vector<TensorValue> cond_outputs; | |||
| GE_CHK_STATUS_RET(executor->GetOutputs(cond_outputs), "[%s] Failed to get cond-output.", cond_->GetName().c_str()); | |||
| if (cond_outputs.empty()) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] Cond output is empty.", task_context.GetNodeName()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| int cond_val = 0; | |||
| GE_CHK_STATUS_RET(CopyTensorValueToHost(cond_outputs[0], cond_val), "[%s] Failed to get cond result.", | |||
| task_context.GetNodeName()); | |||
| is_continue = cond_val != 0; | |||
| return SUCCESS; | |||
| } | |||
| Status WhileOpNodeTask::MoveOutputs2Inputs(TaskContext &task_context) { | |||
| // set outputs to inputs for next iteration | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| auto input_tensor = task_context.MutableInput(i); | |||
| auto output_tensor = task_context.MutableOutput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| GE_CHECK_NOTNULL(output_tensor); | |||
| *input_tensor = *output_tensor; | |||
| output_tensor->Destroy(); | |||
| auto output_tensor_desc = task_context.MutableOutputDesc(i); | |||
| GE_CHECK_NOTNULL(output_tensor_desc); | |||
| GELOGD("[%s] To update input shape[%d] by output shape. from [%s] to [%s]", task_context.GetNodeName(), i, | |||
| task_context.MutableInputDesc(i)->GetShape().ToString().c_str(), | |||
| output_tensor_desc->GetShape().ToString().c_str()); | |||
| *task_context.MutableInputDesc(i) = *output_tensor_desc; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status WhileOpNodeTask::ExecuteOneLoop(TaskContext &task_context, bool &is_continue) const { | |||
| GE_CHK_STATUS_RET(ExecuteCond(task_context, is_continue), "[%s] Failed to execute cond-subgraph", | |||
| task_context.GetNodeName()); | |||
| if (!is_continue) { | |||
| for (int i = 0; i < task_context.NumInputs(); ++i) { | |||
| auto input_tensor = task_context.GetInput(i); | |||
| GE_CHECK_NOTNULL(input_tensor); | |||
| task_context.SetOutput(i, *input_tensor); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| GELOGD("[%s] Start to execute body-subgraph.", task_context.GetNodeName()); | |||
| GE_CHK_STATUS_RET(ExecuteSubgraph(body_, task_context, nullptr), "[%s] Failed to execute cond-subgraph", | |||
| task_context.GetNodeName()); | |||
| GELOGD("[%s] Done executing body-subgraph successfully.", task_context.GetNodeName()); | |||
| // set outputs to inputs for next iteration | |||
| GE_CHK_STATUS_RET(MoveOutputs2Inputs(task_context), "[%s] Failed to move outputs to inputs", | |||
| task_context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| Status ControlOpNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, | |||
| shared_ptr<NodeTask> &task) const { | |||
| auto node_item = model.GetNodeItem(node); | |||
| GE_CHECK_NOTNULL(node_item); | |||
| unique_ptr<ControlOpNodeTask> node_task; | |||
| auto node_type = node->GetType(); | |||
| if (node_type == IF) { | |||
| node_task.reset(new (std::nothrow) IfOpNodeTask()); | |||
| } else if (node_type == CASE) { | |||
| node_task.reset(new (std::nothrow) CaseOpNodeTask()); | |||
| } else if (node_type == WHILE) { | |||
| node_task.reset(new (std::nothrow) WhileOpNodeTask()); | |||
| } else { | |||
| GELOGE(PARAM_INVALID, "[%s] Unsupported type: %s", node->GetName().c_str(), node_type.c_str()); | |||
| return PARAM_INVALID; | |||
| } | |||
| GE_CHECK_NOTNULL(node_task); | |||
| GE_CHK_STATUS_RET(node_task->Init(node, model), "[%s] Failed to init ControlOpNodeTask.", node->GetName().c_str()); | |||
| task = std::move(node_task); | |||
| return SUCCESS; | |||
| } | |||
| Status ControlOpNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { return SUCCESS; } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,100 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ | |||
| #define GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ | |||
| #include <vector> | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| #include "hybrid/model/graph_item.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class ControlOpNodeTask : public NodeTask { | |||
| public: | |||
| virtual Status Init(const NodePtr &node, const HybridModel &model) = 0; | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| Status ExecuteAsync(TaskContext &task_context, std::function<void()> done_callback) override; | |||
| protected: | |||
| virtual Status DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const = 0; | |||
| static Status CopyTensorValueToHost(const TensorValue &tensor_value, int32_t &value); | |||
| static Status ExecuteSubgraph(const GraphItem *subgraph, TaskContext &task_context, | |||
| const std::function<void()> &done_callback); | |||
| }; | |||
| class IfOpNodeTask : public ControlOpNodeTask { | |||
| public: | |||
| Status Init(const NodePtr &node, const HybridModel &model) override; | |||
| protected: | |||
| const GraphItem *SelectBranch(int32_t cond) const; | |||
| Status DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const override; | |||
| private: | |||
| static constexpr int kIfCondIndex = 0; | |||
| static constexpr int kThenBranchIndex = 0; | |||
| static constexpr int kElseBranchIndex = 1; | |||
| const GraphItem *then_ = nullptr; | |||
| const GraphItem *else_ = nullptr; | |||
| }; | |||
| class CaseOpNodeTask : public ControlOpNodeTask { | |||
| public: | |||
| Status Init(const NodePtr &node, const HybridModel &model) override; | |||
| protected: | |||
| const GraphItem *SelectBranch(int32_t branch_index) const; | |||
| Status DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const override; | |||
| private: | |||
| static constexpr int kCaseBranchIndex = 0; | |||
| static constexpr size_t kMaxBranchNum = INT32_MAX; | |||
| static constexpr size_t kMinBranchNum = 1; | |||
| std::vector<const GraphItem *> subgraphs_; | |||
| }; | |||
| class WhileOpNodeTask : public ControlOpNodeTask { | |||
| public: | |||
| Status Init(const NodePtr &node, const HybridModel &model) override; | |||
| protected: | |||
| Status DoExecuteAsync(TaskContext &task_context, const std::function<void()> &done_callback) const override; | |||
| Status ExecuteCond(TaskContext &task_context, bool &is_continue) const; | |||
| static Status MoveOutputs2Inputs(TaskContext &task_context); | |||
| Status ExecuteOneLoop(TaskContext &task_context, bool &is_continue) const; | |||
| private: | |||
| static constexpr int kCondBranchIndex = 0; | |||
| static constexpr int kBodyBranchIndex = 1; | |||
| const GraphItem *cond_ = nullptr; | |||
| const GraphItem *body_ = nullptr; | |||
| }; | |||
| class ControlOpNodeExecutor : public NodeExecutor { | |||
| public: | |||
| Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const override; | |||
| Status PrepareTask(NodeTask &task, TaskContext &context) const override; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ | |||
| @@ -1,207 +0,0 @@ | |||
| /** | |||
| * 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 "hybrid/node_executor/hccl/hccl_node_executor.h" | |||
| #include "graph/manager/util/hcom_util.h" | |||
| #include "framework/common/debug/ge_log.h" | |||
| #include "framework/common/fmk_error_codes.h" | |||
| #include "common/ge/ge_util.h" | |||
| #include "common/ge/plugin_manager.h" | |||
| #include "graph/attr_value.h" | |||
| #include "graph/debug/ge_attr_define.h" | |||
| #include "hccl/hcom.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::HCCL, HcclNodeExecutor); | |||
| Status HcclNodeTask::ExecuteAsync(TaskContext &context, std::function<void()> done_callback) { | |||
| GELOGI("[%s] HcclNodeTask::ExecuteAsync in.", context.GetNodeName()); | |||
| if (context.handle_ == nullptr) { | |||
| GELOGE(FAILED, "hccl handle is nullptr! "); | |||
| return FAILED; | |||
| } | |||
| auto EnqueueHcomOpertion = (hcclResult_t(*)(HcomOpertion, std::function<void(hcclResult_t status)>))dlsym( | |||
| context.handle_, "EnqueueHcomOpertion"); | |||
| if (EnqueueHcomOpertion == nullptr) { | |||
| GELOGE(FAILED, "Failed to invoke EnqueueHcomOpertion hcom unknown node function."); | |||
| if (dlclose(context.handle_) != 0) { | |||
| GELOGW("Failed to close handle %s", dlerror()); | |||
| } | |||
| return FAILED; | |||
| } | |||
| vector<void *> inputs; | |||
| for (int i = 0; i < context.NumInputs(); ++i) { | |||
| TensorValue *tv = context.MutableInput(i); | |||
| GE_CHECK_NOTNULL(tv); | |||
| inputs.emplace_back(tv->MutableData()); | |||
| } | |||
| vector<void *> outputs; | |||
| for (int i = 0; i < context.NumOutputs(); ++i) { | |||
| TensorValue *tv = context.MutableOutput(i); | |||
| GE_CHECK_NOTNULL(tv); | |||
| outputs.emplace_back(tv->MutableData()); | |||
| } | |||
| const NodeItem &node_item = context.GetNodeItem(); | |||
| const OpDescPtr op_desc = MakeShared<OpDesc>(*(node_item.op_desc)); | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| HcomOpertion op_info; | |||
| op_info.hcclType = op_desc->GetType(); | |||
| op_info.inputPtr = inputs.empty() ? nullptr : inputs[0]; | |||
| op_info.outputPtr = outputs.empty() ? nullptr : outputs[0]; | |||
| ge::DataType src_data_type = op_desc->GetInputDescPtr(0)->GetDataType(); | |||
| auto iter = kConstOpHcclDataType.find(static_cast<int64_t>(src_data_type)); | |||
| if (iter == kConstOpHcclDataType.end()) { | |||
| GELOGE(PARAM_INVALID, "kConstOpHcclDataType find failed."); | |||
| return PARAM_INVALID; | |||
| } | |||
| op_info.dataType = iter->second; | |||
| hcclRedOp_t op_type = HCCL_REP_OP_SUM; | |||
| if (op_desc->GetType() == HCOMALLREDUCE || op_desc->GetType() == HCOMREDUCESCATTER || | |||
| op_desc->GetType() == HVDCALLBACKALLREDUCE) { | |||
| GE_CHK_STATUS_RET(HcomOmeUtil::GetHcclOperationType(op_desc, op_type), "GetHcclOperationType failed"); | |||
| op_info.opType = op_type; | |||
| } | |||
| int64_t root_id = 0; | |||
| if (op_desc->GetType() == HCOMBROADCAST) { | |||
| GE_CHK_STATUS_RET(HcomOmeUtil::GetHcclRootId(op_desc, root_id), "GetHcclRootId failed"); | |||
| } | |||
| op_info.root = root_id; | |||
| auto callback = [this](hcclResult_t status) { | |||
| if (status != HCCL_SUCCESS) { | |||
| GELOGE(HCCL_E_INTERNAL, "Call HcomExcutorInitialize failed, ret: 0x%X", status); | |||
| } | |||
| std::lock_guard<std::mutex> lock(this->hccl_mutex_); | |||
| this->cond_.notify_all(); | |||
| GELOGI("hccl callback success."); | |||
| }; | |||
| int32_t count = 0; | |||
| GE_CHK_STATUS_RET(HcomOmeUtil::GetHcomCount(op_desc, static_cast<hcclDataType_t>(op_info.dataType), false, count), | |||
| "GetHcomCount failed"); | |||
| GELOGI("[%s] HcclNodeTask::ExecuteAsync hccl_type %s, count %d, data_type %d, op_type %d, root %d.", | |||
| context.GetNodeName(), op_info.hcclType.c_str(), count, op_info.dataType, op_info.opType, op_info.root); | |||
| op_info.count = count; | |||
| hcclResult_t hccl_ret = EnqueueHcomOpertion(op_info, callback); | |||
| if (hccl_ret != HCCL_SUCCESS) { | |||
| GELOGE(HCCL_E_INTERNAL, "Call HcomExcutorInitialize failed, ret: 0x%X", hccl_ret); | |||
| return HCCL_E_INTERNAL; | |||
| } | |||
| // pending until hccl finished | |||
| std::unique_lock<std::mutex> ulock(hccl_mutex_); | |||
| cond_.wait(ulock); | |||
| context.RegisterCallback(done_callback); | |||
| GELOGI("[%s] HcclNodeTask::ExecuteAsync success.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } | |||
| Status HcclNodeTask::Init(TaskContext &context) { | |||
| GELOGI("[%s] HcclNodeExecutor::Init success.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { | |||
| GELOGI("[%s] HcclNodeExecutor::PrepareTask in.", context.GetNodeName()); | |||
| GE_CHK_STATUS_RET(task.Init(context), "hccl node load hccl so failed."); | |||
| // allocate output mem | |||
| GE_CHK_STATUS_RET(context.AllocateOutputs(), "hccl node task allocate output failed."); | |||
| GE_CHK_STATUS_RET(task.UpdateArgs(context), "hccl node task update args failed."); | |||
| GELOGI("[%s] HcclNodeExecutor::PrepareTask success.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const { | |||
| GELOGI("[%s] HcclNodeExecutor::LoadTask in.", node->GetName().c_str()); | |||
| GE_CHECK_NOTNULL(node); | |||
| task = MakeShared<HcclNodeTask>(); | |||
| GE_CHECK_NOTNULL(task); | |||
| GELOGI("[%s] HcclNodeExecutor::LoadTask success.", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeExecutor::ExecuteTask(NodeTask &task, TaskContext &context, | |||
| const std::function<void()> &callback) const { | |||
| context.handle_ = handle_; | |||
| GE_CHK_STATUS_RET(task.ExecuteAsync(context, callback), "Failed to execute task. node = %s", | |||
| context.GetNodeItem().NodeName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeExecutor::Initialize() { | |||
| std::string file_name = "libhccl.so"; | |||
| std::string path = PluginManager::GetPath(); | |||
| path.append(file_name); | |||
| string canonical_path = RealPath(path.c_str()); | |||
| if (canonical_path.empty()) { | |||
| GELOGW("failed to get realpath of %s", path.c_str()); | |||
| return FAILED; | |||
| } | |||
| GELOGI("FileName:%s, Path:%s.", file_name.c_str(), canonical_path.c_str()); | |||
| handle_ = dlopen(canonical_path.c_str(), RTLD_NOW | RTLD_GLOBAL); | |||
| if (handle_ == nullptr) { | |||
| GELOGE(GE_PLGMGR_SO_NOT_EXIST, "Failed in dlopen %s! ", dlerror()); | |||
| return FAILED; | |||
| } | |||
| auto HcomExcutorInitialize = (hcclResult_t(*)())dlsym(handle_, "HcomExcutorInitialize"); | |||
| if (HcomExcutorInitialize == nullptr) { | |||
| GELOGE(FAILED, "Failed to invoke HcomExcutorInitialize hcom unknown node function."); | |||
| return FAILED; | |||
| } | |||
| hcclResult_t hccl_ret = HcomExcutorInitialize(); | |||
| if (hccl_ret == HCCL_E_PTR) { | |||
| GELOGI("Hccl comm is null, hcom executor initialize is not required."); | |||
| } else if (hccl_ret == HCCL_SUCCESS) { | |||
| GELOGI("Hcom executor initialize success."); | |||
| } else { | |||
| GELOGE(FAILED, "Call HcomExcutorInitialize failed, ret: 0x%X", hccl_ret); | |||
| return FAILED; | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| Status HcclNodeExecutor::Finalize() { | |||
| auto HcomExcutorFinalize = (hcclResult_t(*)())dlsym(handle_, "HcomExcutorFinalize"); | |||
| if (HcomExcutorFinalize == nullptr) { | |||
| GELOGE(FAILED, "Failed to invoke HcomExcutorFinalize hcom unknown node function."); | |||
| return FAILED; | |||
| } | |||
| hcclResult_t hccl_ret = HcomExcutorFinalize(); | |||
| if (hccl_ret != HCCL_SUCCESS) { | |||
| GELOGE(FAILED, "Call HcomExcutorFinalize failed, ret: 0x%X", hccl_ret); | |||
| return FAILED; | |||
| } | |||
| // dlclose file handle | |||
| if (dlclose(handle_) != 0) { | |||
| GELOGW("Failed to close handle %s", dlerror()); | |||
| } | |||
| GELOGI("Hcom executor finalize success."); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,59 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef HYBRID_HCCL_NODE_EXECUTOR_H_ | |||
| #define HYBRID_HCCL_NODE_EXECUTOR_H_ | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| #include "graph/op_desc.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class HybridModel; | |||
| class HcclNodeTask : public NodeTask { | |||
| public: | |||
| HcclNodeTask() {} | |||
| ~HcclNodeTask() {} | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| Status ExecuteAsync(TaskContext &context, std::function<void()> done_callback) override; | |||
| Status Init(TaskContext &context) override; | |||
| private: | |||
| std::shared_ptr<DavinciModel> davinci_model_ = nullptr; | |||
| bool load_flag_ = false; | |||
| std::mutex hccl_mutex_; | |||
| std::condition_variable cond_; | |||
| }; | |||
| class HcclNodeExecutor : public NodeExecutor { | |||
| public: | |||
| Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const; | |||
| Status PrepareTask(NodeTask &task, TaskContext &context) const; | |||
| Status ExecuteTask(NodeTask &task, TaskContext &context, const std::function<void()> &callback) const; | |||
| Status Initialize() override; | |||
| Status Finalize() override; | |||
| ~HcclNodeExecutor() {} | |||
| private: | |||
| void *handle_; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // HYBRID_HCCL_NODE_EXECUTOR_H_ | |||
| @@ -17,12 +17,14 @@ | |||
| #include "hybrid/node_executor/hostcpu/ge_local_node_executor.h" | |||
| #include "graph/debug/ge_attr_define.h" | |||
| #include "framework/common/util.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| #include "framework/common/types.h" | |||
| #include "inc/kernel.h" | |||
| #include "inc/kernel_factory.h" | |||
| #include "common/ge/ge_util.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::GE_LOCAL, GeLocalNodeExecutor); | |||
| const std::unordered_map<std::string, std::vector<uint32_t>> RefInputTask::out_ref_input_index_ = { | |||
| @@ -130,7 +132,7 @@ Status DependInputShapeTask::Execute(TaskContext &context) { | |||
| } | |||
| // alloc output | |||
| GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs(NpuMemoryAllocator::AttrWithDefaultPadding())); | |||
| GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); | |||
| // copy data to output | |||
| for (auto i = 0; i < output_num; ++i) { | |||
| @@ -192,16 +194,6 @@ Status GeLocalNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &no | |||
| node_type.c_str()); | |||
| return MEMALLOC_FAILED; | |||
| } | |||
| } else if (node_type == CONSTANTOP || node_type == VARIABLE) { | |||
| GELOGI("node %s type %s, use ConstantNodeTask.", node->GetName().c_str(), node_type.c_str()); | |||
| auto tensor = model.GetVariable(node->GetName()); | |||
| if (tensor == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to get tensor by name: %s", node->GetName().c_str()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| task = MakeShared<ConstantNodeTask>(tensor); | |||
| GE_CHECK_NOTNULL(task); | |||
| } else { | |||
| GELOGE(UNSUPPORTED, "node %s type %s is not support in GeLocalNodeExecutor now.", node->GetName().c_str(), | |||
| node_type.c_str()); | |||
| @@ -210,20 +202,5 @@ Status GeLocalNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &no | |||
| return SUCCESS; | |||
| } | |||
| ConstantNodeTask::ConstantNodeTask(const TensorValue *tensor) : tensor_(tensor) {} | |||
| Status ConstantNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } | |||
| Status ConstantNodeTask::ExecuteAsync(TaskContext &context, std::function<void()> done_callback) { | |||
| GELOGD("[%s] Start execute.", context.GetNodeName()); | |||
| GE_CHK_STATUS_RET(context.SetOutput(0, *tensor_), "[%s] Failed to set output.", context.GetNodeName()); | |||
| if (done_callback) { | |||
| GELOGD("[%s] Start invoke callback.", context.GetNodeName()); | |||
| done_callback(); | |||
| } | |||
| GELOGD("[%s] Done execute successfully.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -23,6 +23,7 @@ | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class RefInputTask : public NodeTask { | |||
| public: | |||
| explicit RefInputTask(const NodePtr &node) : node_name_(node->GetName()), node_type_(node->GetType()) {} | |||
| @@ -67,18 +68,6 @@ class DependInputShapeTask : public NodeTask { | |||
| static const std::unordered_set<std::string> depend_input_shape_ops_; | |||
| }; | |||
| class ConstantNodeTask : public NodeTask { | |||
| public: | |||
| explicit ConstantNodeTask(const TensorValue *tensor); | |||
| ~ConstantNodeTask() = default; | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| Status ExecuteAsync(TaskContext &context, std::function<void()> done_callback) override; | |||
| private: | |||
| const TensorValue *tensor_; | |||
| }; | |||
| class GeLocalNodeExecutor : public NodeExecutor { | |||
| public: | |||
| Status PrepareTask(NodeTask &task, TaskContext &context) const override; | |||
| @@ -16,7 +16,6 @@ | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| #include "framework/common/debug/log.h" | |||
| #include "graph/utils/node_utils.h" | |||
| #include "init/gelib.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| @@ -26,11 +25,9 @@ namespace { | |||
| const char *const kEngineNameAiCore = "AIcoreEngine"; | |||
| const char *const kEngineNameGeLocal = "DNN_VM_GE_LOCAL_OP_STORE"; | |||
| const char *const kEngineNameAiCpu = "aicpu_kernel"; | |||
| const char *const kEngineNameHccl = "ops_kernel_info_hccl"; | |||
| } // namespace | |||
| Status NodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { | |||
| GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); | |||
| GE_CHK_STATUS_RET_NOLOG(task.UpdateTilingData(context)); // update op_desc before alloc ws | |||
| GE_CHK_STATUS_RET_NOLOG(context.AllocateWorkspaces()); | |||
| GE_CHK_STATUS_RET_NOLOG(task.UpdateArgs(context)); | |||
| return SUCCESS; | |||
| @@ -51,7 +48,6 @@ Status NodeExecutor::CompileTask(const HybridModel &model, const NodePtr &node, | |||
| } | |||
| Status NodeExecutorManager::EnsureInitialized() { | |||
| GE_CHK_STATUS_RET(InitializeExecutors()); | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| if (initialized_) { | |||
| return SUCCESS; | |||
| @@ -60,7 +56,6 @@ Status NodeExecutorManager::EnsureInitialized() { | |||
| engine_mapping_.emplace(kEngineNameAiCore, NodeExecutorManager::ExecutorType::AICORE); | |||
| engine_mapping_.emplace(kEngineNameGeLocal, NodeExecutorManager::ExecutorType::GE_LOCAL); | |||
| engine_mapping_.emplace(kEngineNameAiCpu, NodeExecutorManager::ExecutorType::AICPU_TF); | |||
| engine_mapping_.emplace(kEngineNameHccl, NodeExecutorManager::ExecutorType::HCCL); | |||
| std::shared_ptr<GELib> instance_ptr = GELib::GetInstance(); | |||
| if ((instance_ptr == nullptr) || (!instance_ptr->InitFlag())) { | |||
| @@ -74,6 +69,22 @@ Status NodeExecutorManager::EnsureInitialized() { | |||
| kernel_stores_.emplace(it.first, it.second); | |||
| } | |||
| GELOGI("Start to Initialize NodeExecutors"); | |||
| for (auto &it : builders_) { | |||
| auto engine_type = it.first; | |||
| auto build_fn = it.second; | |||
| GE_CHECK_NOTNULL(build_fn); | |||
| auto executor = std::unique_ptr<NodeExecutor>(build_fn()); | |||
| if (executor == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to create executor for engine type = %d", engine_type); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("Executor of engine type = %d was created successfully", engine_type); | |||
| GE_CHK_STATUS_RET(executor->Initialize(), "Failed to initialize NodeExecutor of type = %d", engine_type); | |||
| executors_.emplace(engine_type, std::move(executor)); | |||
| } | |||
| initialized_ = true; | |||
| GELOGI("Initializing NodeExecutors successfully"); | |||
| return SUCCESS; | |||
| @@ -82,11 +93,6 @@ Status NodeExecutorManager::EnsureInitialized() { | |||
| NodeExecutorManager::ExecutorType NodeExecutorManager::ResolveExecutorType(Node &node) const { | |||
| auto op_type = node.GetType(); | |||
| if (op_type == PARTITIONEDCALL) { | |||
| bool is_dynamic = false; | |||
| (void)NodeUtils::GetNodeUnknownShapeStatus(node, is_dynamic); | |||
| if (is_dynamic) { | |||
| return ExecutorType::DYNAMIC_SUBGRAPH; | |||
| } | |||
| return ExecutorType::COMPILED_SUBGRAPH; | |||
| } | |||
| @@ -95,10 +101,6 @@ NodeExecutorManager::ExecutorType NodeExecutorManager::ResolveExecutorType(Node | |||
| return ExecutorType::GE_LOCAL; | |||
| } | |||
| if (op_type == IF || op_type == CASE || op_type == WHILE) { | |||
| return ExecutorType::CONTROL_OP; | |||
| } | |||
| auto op_desc = node.GetOpDesc(); // checked before | |||
| const auto &lib_name = op_desc->GetOpKernelLibName(); | |||
| auto it = engine_mapping_.find(lib_name); | |||
| @@ -114,11 +116,10 @@ Status NodeExecutorManager::GetExecutor(Node &node, const NodeExecutor **executo | |||
| auto executor_type = ResolveExecutorType(node); | |||
| const auto it = executors_.find(executor_type); | |||
| if (it == executors_.end()) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to get executor by type: %d.", executor_type); | |||
| GELOGE(INTERNAL_ERROR, "Failed to get executor by type: %d", executor_type); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("[%s] Set node executor by type: %d.", node.GetName().c_str(), executor_type); | |||
| *executor = it->second.get(); | |||
| return SUCCESS; | |||
| } | |||
| @@ -131,11 +132,6 @@ void NodeExecutorManager::RegisterExecutorBuilder(NodeExecutorManager::ExecutorT | |||
| Status NodeExecutorManager::CalcOpRunningParam(Node &node) const { | |||
| auto op_desc = node.GetOpDesc(); | |||
| GE_CHECK_NOTNULL(op_desc); | |||
| if (op_desc->GetType() == PARTITIONEDCALL) { | |||
| GELOGD("[%s] Skipping CalcOpRunningParam for PartitionedCall.", node.GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| auto it = kernel_stores_.find(op_desc->GetOpKernelLibName()); | |||
| if (it == kernel_stores_.end()) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to get OpKernelStore. libName = %s, node = %s", | |||
| @@ -143,91 +139,9 @@ Status NodeExecutorManager::CalcOpRunningParam(Node &node) const { | |||
| return INTERNAL_ERROR; | |||
| } | |||
| // calc hccl output size independent, hccl ops kernel manager should GetSize for | |||
| // input which is the output size of input-op, but sometimes return error | |||
| // when multi-thread | |||
| if (op_desc->GetOpKernelLibName() == kEngineNameHccl) { | |||
| for (size_t i = 0; i < op_desc->GetOutputsSize(); ++i) { | |||
| GeTensorDesc output_tensor = op_desc->GetOutputDesc(static_cast<uint32_t>(i)); | |||
| Format format = output_tensor.GetFormat(); | |||
| DataType data_type = output_tensor.GetDataType(); | |||
| GeShape output_shape = output_tensor.GetShape(); | |||
| int64_t output_mem_size = 0; | |||
| GE_CHK_STATUS_RET(TensorUtils::CalcTensorMemSize(output_shape, format, data_type, output_mem_size), | |||
| "hccl calc tensor mem size failed."); | |||
| output_mem_size = | |||
| ((output_mem_size + MEMORY_ALIGN_RATIO * MEMORY_ALIGN_SIZE - 1) / MEMORY_ALIGN_SIZE) * MEMORY_ALIGN_SIZE; | |||
| TensorUtils::SetSize(output_tensor, output_mem_size); | |||
| GE_CHK_STATUS_RET(op_desc->UpdateOutputDesc(static_cast<uint32_t>(i), output_tensor), | |||
| "hccl update output size failed."); | |||
| GELOGD("%s output desc[%u], dim_size: %zu, mem_size: %ld.", node.GetName().c_str(), i, | |||
| output_tensor.GetShape().GetDimNum(), output_mem_size); | |||
| } | |||
| return SUCCESS; | |||
| } | |||
| return it->second->CalcOpRunningParam(node); | |||
| } | |||
| Status NodeExecutorManager::InitializeExecutors() { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| if (executor_initialized_) { | |||
| ++ref_count_; | |||
| GELOGI("Executor is already initialized. add ref count to [%d]", ref_count_); | |||
| return SUCCESS; | |||
| } | |||
| GELOGI("Start to Initialize NodeExecutors"); | |||
| for (auto &it : builders_) { | |||
| auto engine_type = it.first; | |||
| auto build_fn = it.second; | |||
| GE_CHECK_NOTNULL(build_fn); | |||
| auto executor = std::unique_ptr<NodeExecutor>(build_fn()); | |||
| if (executor == nullptr) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to create executor for engine type = %d", engine_type); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| GELOGD("Executor of engine type = %d was created successfully", engine_type); | |||
| auto ret = executor->Initialize(); | |||
| if (ret != SUCCESS) { | |||
| GELOGE(ret, "Failed to initialize NodeExecutor of type = %d, clear executors", engine_type); | |||
| for (auto &executor_it : executors_) { | |||
| executor_it.second->Finalize(); | |||
| } | |||
| executors_.clear(); | |||
| return ret; | |||
| } | |||
| executors_.emplace(engine_type, std::move(executor)); | |||
| } | |||
| ++ref_count_; | |||
| executor_initialized_ = true; | |||
| GELOGI("Initializing NodeExecutors successfully."); | |||
| return SUCCESS; | |||
| } | |||
| void NodeExecutorManager::FinalizeExecutors() { | |||
| std::lock_guard<std::mutex> lk(mu_); | |||
| if (!executor_initialized_) { | |||
| GELOGD("No need for finalizing for not initialized."); | |||
| return; | |||
| } | |||
| if (--ref_count_ > 0) { | |||
| GELOGD("Ref count = %d, do not finalize executors.", ref_count_); | |||
| return; | |||
| } | |||
| GELOGD("Start to invoke Finalize on executors."); | |||
| for (auto &it : executors_) { | |||
| it.second->Finalize(); | |||
| } | |||
| executors_.clear(); | |||
| executor_initialized_ = false; | |||
| GELOGD("Done invoking Finalize successfully."); | |||
| } | |||
| NodeExecutorRegistrar::NodeExecutorRegistrar(NodeExecutorManager::ExecutorType executor_type, | |||
| NodeExecutor *(*builder)()) { | |||
| NodeExecutorManager::GetInstance().RegisterExecutorBuilder(executor_type, builder); | |||
| @@ -14,182 +14,70 @@ | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ | |||
| #define GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ | |||
| #ifndef GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ | |||
| #define GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ | |||
| #include "external/ge/ge_api_error_codes.h" | |||
| #include "common/opskernel/ops_kernel_info_store.h" | |||
| #include "graph/node.h" | |||
| #include "proto/task.pb.h" | |||
| #include "task_context.h" | |||
| namespace ge { | |||
| const uint32_t MEMORY_ALIGN_RATIO = 2; | |||
| const uint32_t MEMORY_ALIGN_SIZE = 32; | |||
| namespace hybrid { | |||
| class HybridModel; | |||
| // Base class of Node Task | |||
| class NodeTask { | |||
| public: | |||
| NodeTask() = default; | |||
| virtual ~NodeTask() = default; | |||
| /** | |||
| * Update tiling data | |||
| * @param context instance of TaskContext | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status UpdateTilingData(TaskContext &context) { return SUCCESS; } | |||
| /** | |||
| * Init | |||
| * @param context instance of TaskContext | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status Init(TaskContext &context) { return SUCCESS; } | |||
| /** | |||
| * Whether this task supports dynamic shape | |||
| * @return true if this task supports dynamic shape, false otherwise | |||
| */ | |||
| virtual bool IsSupportDynamicShape() { return true; } | |||
| /** | |||
| * Update args for execution | |||
| * @param context instance of TaskContext | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status UpdateArgs(TaskContext &context) = 0; | |||
| /** | |||
| * Execute task async | |||
| * @param context instance of TaskContext | |||
| * @param done_callback callback function, will be invoked after task is done | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status ExecuteAsync(TaskContext &context, std::function<void()> done_callback) = 0; | |||
| virtual Status Init(TaskContext &context) { return SUCCESS; } | |||
| }; | |||
| // Node executor | |||
| class NodeExecutor { | |||
| public: | |||
| NodeExecutor() = default; | |||
| virtual ~NodeExecutor() = default; | |||
| /** | |||
| * Initialize node executor | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status Initialize() { return SUCCESS; } | |||
| /** | |||
| * Finalize node executor | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status Finalize() { return SUCCESS; } | |||
| /** | |||
| * Load task in load stage | |||
| * @param model instance of HybridModel | |||
| * @param node node | |||
| * @param task generated node task | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status LoadTask(const HybridModel &model, const NodePtr &node, std::shared_ptr<NodeTask> &task) const; | |||
| /** | |||
| * Compile task in run stage | |||
| * @param model instance of HybridModel | |||
| * @param node node | |||
| * @param task generated node task | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status CompileTask(const HybridModel &model, const NodePtr &node, std::shared_ptr<NodeTask> &task) const; | |||
| /** | |||
| * Preparation actions before execution | |||
| * @param task instance of NodeTask | |||
| * @param context instance of TaskContext | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status PrepareTask(NodeTask &task, TaskContext &context) const; | |||
| /** | |||
| * Execute task | |||
| * @param task instance of NodeTask | |||
| * @param context instance of TaskContext | |||
| * @param callback callback function which will be invoked after computation is done | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| virtual Status ExecuteTask(NodeTask &task, TaskContext &context, const std::function<void()> &callback) const; | |||
| }; | |||
| class NodeExecutorManager { | |||
| public: | |||
| enum class ExecutorType { | |||
| AICORE, | |||
| AICPU_TF, | |||
| AICPU_CUSTOM, | |||
| COMPILED_SUBGRAPH, | |||
| DYNAMIC_SUBGRAPH, | |||
| GE_LOCAL, | |||
| CONTROL_OP, | |||
| HCCL, | |||
| RESERVED | |||
| }; | |||
| enum class ExecutorType { AICORE, GE_LOCAL, AICPU_TF, AICPU_CUSTOM, COMPILED_SUBGRAPH, HCCL, RESERVED }; | |||
| static NodeExecutorManager &GetInstance() { | |||
| static NodeExecutorManager instance; | |||
| return instance; | |||
| } | |||
| /** | |||
| * Register build of executor | |||
| * @param executor_type type of executor | |||
| * @param builder build function | |||
| */ | |||
| Status CalcOpRunningParam(Node &node) const; | |||
| void RegisterExecutorBuilder(ExecutorType executor_type, const std::function<NodeExecutor *()> &builder); | |||
| /** | |||
| * Initialize executor if needed | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status EnsureInitialized(); | |||
| Status InitializeExecutors(); | |||
| void FinalizeExecutors(); | |||
| /** | |||
| * CalcOpRunningParam | |||
| * @param node node | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status CalcOpRunningParam(Node &node) const; | |||
| /** | |||
| * Get executor by node | |||
| * @param node node | |||
| * @param executor executor | |||
| * @return SUCCESS on success, error code otherwise | |||
| */ | |||
| Status GetExecutor(Node &node, const NodeExecutor **executor) const; | |||
| /** | |||
| * Resolve executor type by node | |||
| * @param node node | |||
| * @return executor type | |||
| */ | |||
| ExecutorType ResolveExecutorType(Node &node) const; | |||
| private: | |||
| std::map<ExecutorType, std::unique_ptr<NodeExecutor>> executors_; | |||
| std::map<ExecutorType, std::function<NodeExecutor *()>> builders_; | |||
| std::map<std::string, std::shared_ptr<OpsKernelInfoStore>> kernel_stores_; | |||
| std::map<std::string, NodeExecutorManager::ExecutorType> engine_mapping_; | |||
| std::mutex mu_; | |||
| bool initialized_ = false; | |||
| bool executor_initialized_ = false; | |||
| int ref_count_ = 0; | |||
| }; | |||
| class NodeExecutorRegistrar { | |||
| @@ -211,4 +99,4 @@ class NodeExecutorRegistrar { | |||
| ::ge::hybrid::NodeExecutorRegistrar( \ | |||
| engine_type, []() -> ::ge::hybrid::NodeExecutor * { return new (std::nothrow) executor(); }) | |||
| #endif // GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ | |||
| #endif // GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ | |||
| @@ -1,81 +0,0 @@ | |||
| /** | |||
| * 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 "partitioned_call_node_executor.h" | |||
| #include "graph/utils/node_utils.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::DYNAMIC_SUBGRAPH, PartitionedCallNodeExecutor); | |||
| PartitionedCallNodeTask::PartitionedCallNodeTask(const GraphItem *graph_item) : graph_item_(graph_item) {} | |||
| PartitionedCallNodeTask::~PartitionedCallNodeTask() { | |||
| GELOGD("[%s] PartitionedCallNodeTask destroyed.", graph_item_->GetName().c_str()); | |||
| } | |||
| Status PartitionedCallNodeTask::Init(TaskContext &context) { | |||
| auto execution_context = const_cast<GraphExecutionContext *>(context.GetExecutionContext()); | |||
| subgraph_executor_.reset(new (std::nothrow) SubgraphExecutor(graph_item_, execution_context)); | |||
| GE_CHECK_NOTNULL(subgraph_executor_); | |||
| return SUCCESS; | |||
| } | |||
| Status PartitionedCallNodeTask::ExecuteAsync(TaskContext &context, std::function<void()> done_callback) { | |||
| GE_CHK_STATUS_RET(subgraph_executor_->ExecuteAsync(context), "[%s] Failed to set inputs", | |||
| graph_item_->GetName().c_str()); | |||
| auto callback = [=]() { Callback(done_callback); }; | |||
| GE_CHK_STATUS_RET(context.RegisterCallback(callback), "[%s] Failed to register callback", | |||
| graph_item_->GetName().c_str()); | |||
| GELOGD("[%s] Done executing subgraph successfully.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status PartitionedCallNodeTask::Callback(const std::function<void()> &done_callback) { | |||
| GELOGD("[%s] On subgraph callback", graph_item_->GetName().c_str()); | |||
| if (done_callback != nullptr) { | |||
| done_callback(); | |||
| } | |||
| GELOGD("[%s] To release sub graph tensors.", graph_item_->GetName().c_str()); | |||
| subgraph_executor_.reset(); | |||
| GELOGD("[%s] Done releasing sub graph tensors.", graph_item_->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status PartitionedCallNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } | |||
| Status PartitionedCallNodeExecutor::LoadTask(const ge::hybrid::HybridModel &model, const ge::NodePtr &node, | |||
| std::shared_ptr<NodeTask> &task) const { | |||
| GELOGD("Load dynamic partitioned call: [%s]", node->GetName().c_str()); | |||
| auto subgraph = NodeUtils::GetSubgraph(*node, 0); | |||
| GE_CHECK_NOTNULL(subgraph); | |||
| auto partitioned_call = model.GetSubgraphItem(subgraph); | |||
| GE_CHECK_NOTNULL(partitioned_call); | |||
| task.reset(new (std::nothrow) PartitionedCallNodeTask(partitioned_call)); | |||
| GE_CHECK_NOTNULL(task); | |||
| GELOGD("Done loading dynamic partitioned call: [%s]", node->GetName().c_str()); | |||
| return SUCCESS; | |||
| } | |||
| Status PartitionedCallNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { | |||
| GE_CHK_STATUS_RET(task.Init(context), "[%s] Failed to init task.", context.GetNodeName()); | |||
| return SUCCESS; | |||
| } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -1,54 +0,0 @@ | |||
| /** | |||
| * 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. | |||
| */ | |||
| #ifndef GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ | |||
| #define GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ | |||
| #include "hybrid/node_executor/node_executor.h" | |||
| #include "hybrid/model/hybrid_model.h" | |||
| #include "hybrid/executor/node_state.h" | |||
| #include "hybrid/executor/subgraph_executor.h" | |||
| #include "common/thread_pool.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class PartitionedCallNodeTask : public NodeTask { | |||
| public: | |||
| explicit PartitionedCallNodeTask(const GraphItem *graph_item); | |||
| ~PartitionedCallNodeTask() override; | |||
| Status Init(TaskContext &context) override; | |||
| Status UpdateArgs(TaskContext &context) override; | |||
| Status ExecuteAsync(TaskContext &context, std::function<void()> done_callback) override; | |||
| private: | |||
| Status Callback(const std::function<void()> &done_callback); | |||
| const GraphItem *graph_item_; | |||
| std::unique_ptr<SubgraphExecutor> subgraph_executor_; | |||
| GraphExecutionContext *context_ = nullptr; | |||
| }; | |||
| class PartitionedCallNodeExecutor : public NodeExecutor { | |||
| public: | |||
| Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr<NodeTask> &task) const override; | |||
| Status PrepareTask(NodeTask &task, TaskContext &context) const override; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| #endif // GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ | |||
| @@ -19,16 +19,12 @@ | |||
| #include "framework/common/debug/log.h" | |||
| #include "graph/utils/tensor_utils.h" | |||
| #include "hybrid/executor/hybrid_execution_context.h" | |||
| #include "hybrid/executor/subgraph_executor.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| TaskContext::TaskContext(GraphExecutionContext *execution_context, const NodeItem *node_item, | |||
| SubgraphContext *subgraph_context) | |||
| : node_item_(node_item), execution_context_(execution_context), subgraph_context_(subgraph_context) {} | |||
| TaskContext::TaskContext(GraphExecutionContext *execution_context) : execution_context_(execution_context) {} | |||
| TaskContext::~TaskContext() { | |||
| GELOGD("[%s] TaskContext destroyed.", node_item_->NodeName().c_str()); | |||
| GELOGD("To execute ~TaskContext(). node = %s", node_item_->NodeName().c_str()); | |||
| for (auto ws_addr : workspaces_) { | |||
| execution_context_->allocator->Deallocate(ws_addr); | |||
| } | |||
| @@ -42,28 +38,19 @@ TaskContext::~TaskContext() { | |||
| } | |||
| } | |||
| std::unique_ptr<TaskContext> TaskContext::Create(const NodeItem &node_item, GraphExecutionContext *execution_context, | |||
| SubgraphContext *subgraph_context) { | |||
| GELOGI("[%s] To create task context, input start = %d, num_inputs = %d, output start = %d, num_outputs = %d.", | |||
| std::unique_ptr<TaskContext> TaskContext::Create(const NodeItem &node_item, GraphExecutionContext *graph_context) { | |||
| GELOGI("To create task context for node %s, input start = %d, num_inputs = %d, output start = %d, num_outputs = %d", | |||
| node_item.NodeName().c_str(), node_item.input_start, node_item.num_inputs, node_item.output_start, | |||
| node_item.num_outputs); | |||
| if (node_item.input_start < 0 || node_item.output_start < 0) { | |||
| GELOGE(INTERNAL_ERROR, "NodeItem not property initialized. input_start = %d, output_start = %d", | |||
| node_item.input_start, node_item.output_start); | |||
| return nullptr; | |||
| } | |||
| auto task_context = | |||
| std::unique_ptr<TaskContext>(new (std::nothrow) TaskContext(execution_context, &node_item, subgraph_context)); | |||
| auto task_context = std::unique_ptr<TaskContext>(new (std::nothrow) TaskContext(graph_context)); | |||
| if (task_context == nullptr) { | |||
| GELOGE(MEMALLOC_FAILED, "[%s] Failed to create instance of TaskContext.", node_item.NodeName().c_str()); | |||
| GELOGE(MEMALLOC_FAILED, "Failed to create instance of TaskContext. node = %s", node_item.NodeName().c_str()); | |||
| return nullptr; | |||
| } | |||
| task_context->node_item_ = &node_item; | |||
| task_context->inputs_start_ = subgraph_context->all_inputs_.data() + node_item.input_start; | |||
| task_context->outputs_start_ = subgraph_context->all_outputs_.data() + node_item.output_start; | |||
| task_context->iteration_ = execution_context->iteration; | |||
| task_context->inputs_start_ = graph_context->all_inputs.data() + node_item.input_start; | |||
| task_context->outputs_start_ = graph_context->all_outputs.data() + node_item.output_start; | |||
| return task_context; | |||
| } | |||
| @@ -72,7 +59,7 @@ int TaskContext::NumInputs() const { return node_item_->num_inputs; } | |||
| int TaskContext::NumOutputs() const { return node_item_->num_outputs; } | |||
| TensorValue *TaskContext::MutableInput(int index) { | |||
| if (index < 0 || index >= node_item_->num_inputs) { | |||
| if (index < 0 || index > node_item_->num_inputs) { | |||
| GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_inputs = %d", index, node_item_->num_inputs); | |||
| return nullptr; | |||
| } | |||
| @@ -81,7 +68,7 @@ TensorValue *TaskContext::MutableInput(int index) { | |||
| } | |||
| const TensorValue *TaskContext::GetOutput(int index) const { | |||
| if (index < 0 || index >= node_item_->num_outputs) { | |||
| if (index < 0 || index > node_item_->num_outputs) { | |||
| GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_outputs = %d", index, node_item_->num_outputs); | |||
| return nullptr; | |||
| } | |||
| @@ -90,7 +77,7 @@ const TensorValue *TaskContext::GetOutput(int index) const { | |||
| } | |||
| TensorValue *TaskContext::MutableOutput(int index) { | |||
| if (index < 0 || index >= node_item_->num_outputs) { | |||
| if (index < 0 || index > node_item_->num_outputs) { | |||
| GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_outputs = %d", index, node_item_->num_outputs); | |||
| return nullptr; | |||
| } | |||
| @@ -110,7 +97,7 @@ void *TaskContext::MutableWorkspace(int index) { | |||
| } | |||
| const TensorValue *TaskContext::GetInput(int index) const { | |||
| if (index < 0 || index >= node_item_->num_inputs) { | |||
| if (index < 0 || index > node_item_->num_inputs) { | |||
| GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_inputs = %d", index, node_item_->num_inputs); | |||
| return nullptr; | |||
| } | |||
| @@ -133,14 +120,7 @@ Status TaskContext::AllocateWorkspaces() { | |||
| } | |||
| Status TaskContext::RegisterCallback(const std::function<void()> &callback_fun) const { | |||
| auto ret = execution_context_->callback_manager->RegisterCallback(callback_fun); | |||
| if (ret != SUCCESS) { | |||
| GELOGE(ret, "[%s] Failed to register callback", GetNodeName()); | |||
| execution_context_->callback_manager->Destroy(); | |||
| return ret; | |||
| } | |||
| return SUCCESS; | |||
| return execution_context_->callback_manager->RegisterCallback(callback_fun); | |||
| } | |||
| string TaskContext::TensorDesc2String(const GeTensorDesc &desc) { | |||
| @@ -157,7 +137,7 @@ string TaskContext::TensorDesc2String(const GeTensorDesc &desc) { | |||
| return ss.str(); | |||
| } | |||
| Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor, AllocationAttr *attr) { | |||
| Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor) { | |||
| int64_t size = 0; | |||
| if (ge::TensorUtils::GetSize(tensor_desc, size) != GRAPH_SUCCESS) { | |||
| GELOGE(INTERNAL_ERROR, "Failed to get tensor size"); | |||
| @@ -168,14 +148,13 @@ Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue | |||
| GELOGW("size from tensor_desc == 0"); | |||
| } | |||
| auto buffer = TensorBuffer::Create(execution_context_->allocator, size, attr); | |||
| auto buffer = TensorBuffer::Create(execution_context_->allocator, size); | |||
| GE_CHECK_NOTNULL(buffer); | |||
| tensor = TensorValue(shared_ptr<TensorBuffer>(buffer.release())); | |||
| return SUCCESS; | |||
| } | |||
| Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor, | |||
| AllocationAttr *attr) { | |||
| Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor) { | |||
| GELOGI("To allocate output for node: %s. index = %d, tensor desc = %s", node_item_->NodeName().c_str(), index, | |||
| TensorDesc2String(tensor_desc).c_str()); | |||
| @@ -199,29 +178,9 @@ Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, T | |||
| GE_CHECK_NOTNULL(ref_tensor); | |||
| outputs_start_[index] = *ref_tensor; | |||
| } else { | |||
| auto reuse_input = node_item_->reuse_inputs.find(index); | |||
| if (reuse_input != node_item_->reuse_inputs.end()) { | |||
| GELOGD("[%s] Output[%d] is referenced to input[%d]", GetNodeName(), index, reuse_input->second); | |||
| outputs_start_[index] = inputs_start_[reuse_input->second]; | |||
| } else { | |||
| GE_CHK_STATUS_RET_NOLOG(AllocateTensor(tensor_desc, outputs_start_[index], attr)); | |||
| GELOGD("Allocating output successfully. node: %s. index = %d, size = %zu", node_item_->NodeName().c_str(), index, | |||
| outputs_start_[index].GetSize()); | |||
| } | |||
| } | |||
| // Temp modification | |||
| if (node_item_->node_type == "UnsortedSegmentSum" || node_item_->node_type == "UnsortedSegmentSumD" || | |||
| node_item_->node_type == "ScatterNd") { | |||
| auto &out_tensor = outputs_start_[index]; | |||
| GELOGD("[%s] clear output tensor: %s", GetNodeName(), out_tensor.DebugString().c_str()); | |||
| auto *ctx = GetExecutionContext(); | |||
| string name = "rtMemsetAsync" + node_item_->node_name; | |||
| RegisterCallback([ctx, name]() { RECORD_CALLBACK_EVENT(ctx, name.c_str(), "[Compute] Start"); }); | |||
| RECORD_EXECUTION_EVENT(GetExecutionContext(), node_item_->node_name.c_str(), "[rtMemsetAsync] Start"); | |||
| GE_CHK_RT_RET(rtMemsetAsync(out_tensor.MutableData(), out_tensor.GetSize(), 0, out_tensor.GetSize(), GetStream())); | |||
| RECORD_EXECUTION_EVENT(GetExecutionContext(), node_item_->node_name.c_str(), "[rtMemsetAsync] End"); | |||
| RegisterCallback([ctx, name]() { RECORD_CALLBACK_EVENT(ctx, name.c_str(), "[Compute] End"); }); | |||
| GE_CHK_STATUS_RET_NOLOG(AllocateTensor(tensor_desc, outputs_start_[index])); | |||
| GELOGD("Allocating output successfully. node: %s. index = %d, size = %zu", node_item_->NodeName().c_str(), index, | |||
| outputs_start_[index].GetSize()); | |||
| } | |||
| if (execution_context_->trace_enabled) { | |||
| @@ -235,11 +194,11 @@ Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, T | |||
| return SUCCESS; | |||
| } | |||
| Status TaskContext::AllocateOutputs(AllocationAttr *attr) { | |||
| Status TaskContext::AllocateOutputs() { | |||
| for (int i = 0; i < node_item_->num_outputs; ++i) { | |||
| const auto &output_desc = node_item_->op_desc->MutableOutputDesc(i); | |||
| GE_CHECK_NOTNULL(output_desc); | |||
| GE_CHK_STATUS_RET_NOLOG(AllocateOutput(i, *output_desc, nullptr, attr)); | |||
| GE_CHK_STATUS_RET_NOLOG(AllocateOutput(i, *output_desc, nullptr)); | |||
| } | |||
| return SUCCESS; | |||
| @@ -271,7 +230,7 @@ Status TaskContext::SetOutput(int index, const TensorValue &tensor) { | |||
| rtStream_t TaskContext::GetStream() { return execution_context_->stream; } | |||
| int64_t TaskContext::GetSessionId() const { return execution_context_->session_id; } | |||
| int64_t TaskContext::GetSessionId() { return execution_context_->session_id; } | |||
| Status TaskContext::GetStatus() const { return status_; } | |||
| @@ -279,13 +238,7 @@ void TaskContext::SetStatus(Status status) { status_ = status; } | |||
| Status TaskContext::AllocateWorkspace(size_t size, void **buffer, void *ori_addr) { | |||
| GE_CHECK_NOTNULL(buffer); | |||
| if (ori_addr == nullptr) { | |||
| *buffer = execution_context_->allocator->Allocate(size, nullptr); | |||
| } else { | |||
| AllocationAttr attr(ori_addr); | |||
| *buffer = execution_context_->allocator->Allocate(size, &attr); | |||
| } | |||
| *buffer = execution_context_->allocator->Allocate(size, ori_addr); | |||
| if (*buffer == nullptr) { | |||
| GELOGE(MEMALLOC_FAILED, "Failed to allocate workspace of size = %zu", size); | |||
| return MEMALLOC_FAILED; | |||
| @@ -308,21 +261,16 @@ Status TaskContext::PropagateOutputs() { | |||
| for (auto &dst_input_index_and_node : output_nodes) { | |||
| auto dst_input_idx = dst_input_index_and_node.first; | |||
| auto dst_node_item = dst_input_index_and_node.second; | |||
| auto input_offset = dst_node_item->input_start + dst_input_idx; | |||
| GELOGI( | |||
| "Propagate output of node %s, output index = %d, dst node = %s, " | |||
| "dst_input_index = %d, dst_input_offset = %d.", | |||
| node_item_->NodeName().c_str(), i, dst_node_item->NodeName().c_str(), dst_input_idx, input_offset); | |||
| if (subgraph_context_->all_inputs_.size() <= static_cast<size_t>(input_offset)) { | |||
| GELOGE(INTERNAL_ERROR, "[%s] input index out of range. index = %d, total input num = %zu", GetNodeName(), | |||
| input_offset, subgraph_context_->all_inputs_.size()); | |||
| return INTERNAL_ERROR; | |||
| } | |||
| subgraph_context_->all_inputs_[input_offset] = *tensor; | |||
| "dst_input_index = %d, dst_input_offset = %d, addr = %p", | |||
| node_item_->NodeName().c_str(), i, dst_node_item->NodeName().c_str(), dst_input_idx, | |||
| dst_node_item->input_start + dst_input_idx, | |||
| execution_context_->all_inputs.data() + dst_node_item->input_start + dst_input_idx); | |||
| execution_context_->all_inputs[dst_node_item->input_start + dst_input_idx] = *tensor; | |||
| if (execution_context_->trace_enabled) { | |||
| subgraph_context_->all_inputs_[input_offset].SetName(node_item_->NodeName() + "_in_" + std::to_string(i)); | |||
| execution_context_->all_inputs[dst_node_item->input_start + dst_input_idx].SetName(node_item_->NodeName() + | |||
| "_in_" + std::to_string(i)); | |||
| } | |||
| } | |||
| } | |||
| @@ -341,37 +289,5 @@ void TaskContext::ReleaseInput(int index) { | |||
| GELOGD("[%s] Tensor of input[%d] released", GetNodeName(), index); | |||
| } | |||
| } | |||
| ConstGeTensorDescPtr TaskContext::GetOutputDesc(int index) { | |||
| return node_item_->op_desc->MutableOutputDesc(static_cast<uint32_t>(index)); | |||
| } | |||
| ConstGeTensorDescPtr TaskContext::GetInputDesc(int index) { | |||
| return node_item_->op_desc->MutableInputDesc(static_cast<uint32_t>(index)); | |||
| } | |||
| GeTensorDescPtr TaskContext::MutableInputDesc(int index) { | |||
| return node_item_->op_desc->MutableInputDesc(static_cast<uint32_t>(index)); | |||
| } | |||
| GeTensorDescPtr TaskContext::MutableOutputDesc(int index) { | |||
| return node_item_->op_desc->MutableOutputDesc(static_cast<uint32_t>(index)); | |||
| } | |||
| bool TaskContext::IsForceInferShape() const { return force_infer_shape_; } | |||
| void TaskContext::SetForceInferShape(bool force_infer_shape) { force_infer_shape_ = force_infer_shape; } | |||
| void TaskContext::NodeDone() { subgraph_context_->NodeDone(node_item_->node); } | |||
| void TaskContext::OnError(Status error) { subgraph_context_->OnError(error); } | |||
| bool TaskContext::IsTraceEnabled() const { return execution_context_->trace_enabled; } | |||
| TensorValue *TaskContext::GetVariable(const std::string &name) { return execution_context_->model->GetVariable(name); } | |||
| uint64_t TaskContext::GetIterationNumber() const { return iteration_; } | |||
| bool TaskContext::IsDumpEnabled() const { return execution_context_->dump_enabled; } | |||
| } // namespace hybrid | |||
| } // namespace ge | |||
| @@ -22,19 +22,16 @@ | |||
| #include <vector> | |||
| #include "external/ge/ge_api_error_codes.h" | |||
| #include "hybrid/common/tensor_value.h" | |||
| #include "hybrid/common/npu_memory_allocator.h" | |||
| #include "hybrid/executor/rt_callback_manager.h" | |||
| #include "hybrid/model/node_item.h" | |||
| namespace ge { | |||
| namespace hybrid { | |||
| class GraphExecutionContext; | |||
| class SubgraphContext; | |||
| class TaskContext { | |||
| public: | |||
| static std::unique_ptr<TaskContext> Create(const NodeItem &node_item, GraphExecutionContext *execution_context, | |||
| SubgraphContext *subgraph_context); | |||
| static std::unique_ptr<TaskContext> Create(const NodeItem &node_item, GraphExecutionContext *graph_context); | |||
| ~TaskContext(); | |||
| @@ -44,33 +41,19 @@ class TaskContext { | |||
| const NodeItem &GetNodeItem() const; | |||
| const char *GetNodeName() const; | |||
| TensorValue *MutableInput(int index); | |||
| ConstGeTensorDescPtr GetInputDesc(int index); | |||
| ConstGeTensorDescPtr GetOutputDesc(int index); | |||
| GeTensorDescPtr MutableInputDesc(int index); | |||
| GeTensorDescPtr MutableOutputDesc(int index); | |||
| void ReleaseInput(int index); | |||
| const TensorValue *GetInput(int index) const; | |||
| const TensorValue *GetOutput(int index) const; | |||
| TensorValue *MutableOutput(int index); | |||
| TensorValue *GetVariable(const std::string &name); | |||
| rtStream_t GetStream(); | |||
| int64_t GetSessionId() const; | |||
| uint64_t GetIterationNumber() const; | |||
| void NodeDone(); | |||
| void OnError(Status error); | |||
| int64_t GetSessionId(); | |||
| Status SetOutput(int index, const TensorValue &tensor); | |||
| Status AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor, | |||
| AllocationAttr *attr = nullptr); | |||
| Status AllocateOutputs(AllocationAttr *attr = nullptr); | |||
| Status AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor); | |||
| Status AllocateOutputs(); | |||
| Status AllocateWorkspaces(); | |||
| Status AllocateWorkspace(size_t size, void **buffer, void *ori_addr = nullptr); | |||
| bool IsTraceEnabled() const; | |||
| bool IsDumpEnabled() const; | |||
| const GraphExecutionContext *GetExecutionContext() { return execution_context_; } | |||
| Status AllocateTemp(size_t size, TensorValue &tensor); | |||
| @@ -85,25 +68,17 @@ class TaskContext { | |||
| void SetStatus(Status status); | |||
| bool IsForceInferShape() const; | |||
| void SetForceInferShape(bool force_infer_shape); | |||
| void *handle_ = nullptr; | |||
| private: | |||
| TaskContext(GraphExecutionContext *execution_context, const NodeItem *node_item, SubgraphContext *subgraph_context); | |||
| explicit TaskContext(GraphExecutionContext *execution_context); | |||
| TensorValue *inputs_start_ = nullptr; | |||
| TensorValue *outputs_start_ = nullptr; | |||
| static string TensorDesc2String(const GeTensorDesc &desc); | |||
| Status AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor, AllocationAttr *attr); | |||
| Status AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor); | |||
| const NodeItem *node_item_ = nullptr; | |||
| bool force_infer_shape_ = false; | |||
| GraphExecutionContext *execution_context_; | |||
| SubgraphContext *subgraph_context_; | |||
| TensorValue *inputs_start_ = nullptr; | |||
| TensorValue *outputs_start_ = nullptr; | |||
| const NodeItem *node_item_ = nullptr; | |||
| Status status_ = SUCCESS; | |||
| std::vector<void *> workspaces_; | |||
| uint64_t iteration_ = 0; | |||
| }; | |||
| } // namespace hybrid | |||
| } // namespace ge | |||