已合并
【PR】: Revert HostCPU 融合 Codegen 迁移至标准 CustomOp SO #4667
yangyongqiang创建于 4 天前
【PR】: Revert HostCPU 融合 Codegen 迁移至标准 CustomOp SO #4667
已合并
共 33 个文件变更+4512-1591
| @@ -606,9 +606,7 @@ Status ModelHelper::SaveAutofuseSoBin(const GeRootModelPtr &ge_root_model) { | |||
| 606 | if (bin_file_buffer != nullptr) { | 606 | if (bin_file_buffer != nullptr) { |
| 607 | GELOGD("bin_file_buffer already exists, sync autofuse so to op_so_store_."); | 607 | GELOGD("bin_file_buffer already exists, sync autofuse so to op_so_store_."); |
| 608 | for (const auto &bin_entry : *bin_file_buffer) { | 608 | for (const auto &bin_entry : *bin_file_buffer) { |
| 609 | - if ((bin_entry.second != nullptr) && (bin_entry.second->GetSoBinType() == SoBinType::kAutofuse)) { | 609 | + op_so_store_.AddKernel(bin_entry.second); |
| 610 | - op_so_store_.AddKernel(bin_entry.second); | ||
| 611 | - } | ||
| 612 | } | 610 | } |
| 613 | return SUCCESS; | 611 | return SUCCESS; |
| 614 | } | 612 | } |
| @@ -625,21 +623,8 @@ Status ModelHelper::SaveCustomOpSoBin(const GeRootModelPtr &ge_root_model) { | |||
| 625 | if (!OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)) { | 623 | if (!OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)) { |
| 626 | return SUCCESS; | 624 | return SUCCESS; |
| 627 | } | 625 | } |
| 628 | - auto root_graph = ge_root_model->GetRootGraph(); | ||
| 629 | - GE_ASSERT_NOTNULL(root_graph); | ||
| 630 | - size_t embedded_so_num = 0U; | ||
| 631 | - const auto so_buffer = root_graph->GetExtAttr<std::map<std::string, ge::OpSoBinPtr>>("bin_file_buffer"); | ||
| 632 | - if (so_buffer != nullptr) { | ||
| 633 | - for (const auto &entry : *so_buffer) { | ||
| 634 | - if ((entry.second != nullptr) && (entry.second->GetSoBinType() == SoBinType::kCustomOp)) { | ||
| 635 | - op_so_store_.AddKernel(entry.second); | ||
| 636 | - ++embedded_so_num; | ||
| 637 | - } | ||
| 638 | - } | ||
| 639 | - } | ||
| 640 | GE_ASSERT_SUCCESS(LoadAndStoreOppSo(ge_root_model->GetCustomOpSoSet(), SoBinType::kCustomOp)); | 626 | GE_ASSERT_SUCCESS(LoadAndStoreOppSo(ge_root_model->GetCustomOpSoSet(), SoBinType::kCustomOp)); |
| 641 | - GELOGI("[CustomOp]Save %zu path-based and %zu embedded custom op so to OpSoStore success.", | 627 | + GELOGI("[CustomOp]Save %zu custom op so to OpSoStore success.", ge_root_model->GetCustomOpSoSet().size()); |
| 642 | - ge_root_model->GetCustomOpSoSet().size(), embedded_so_num); | ||
| 643 | return SUCCESS; | 628 | return SUCCESS; |
| 644 | } | 629 | } |
| 645 | 630 | ||
| @@ -32,8 +32,6 @@ | |||
| 32 | 32 | ||
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | - | ||
| 36 | - | ||
| 37 | 35 | ||
| 38 | 36 | ||
| 39 | namespace ge { | 37 | namespace ge { |
| @@ -173,20 +171,6 @@ Status CollectCustomOpTypesFromGraph(const ComputeGraphPtr &graph, const CustomO | |||
| 173 | } | 171 | } |
| 174 | return SUCCESS; | 172 | return SUCCESS; |
| 175 | } | 173 | } |
| 176 | - | ||
| 177 | -bool IsEmbeddedHostCpuFusionSo(const ComputeGraphPtr &root_graph, const std::string &op_type) { | ||
| 178 | - if (root_graph == nullptr) { | ||
| 179 | - return false; | ||
| 180 | - } | ||
| 181 | - const auto so_buffer = root_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer"); | ||
| 182 | - if (so_buffer == nullptr) { | ||
| 183 | - return false; | ||
| 184 | - } | ||
| 185 | - const std::string so_key = std::string(kFusedHostCpuSoVendor) + "/lib" + op_type + ".so"; | ||
| 186 | - const auto so_it = so_buffer->find(so_key); | ||
| 187 | - return (so_it != so_buffer->cend()) && (so_it->second != nullptr) && | ||
| 188 | - (so_it->second->GetSoBinType() == SoBinType::kCustomOp); | ||
| 189 | -} | ||
| 190 | } // namespace | 174 | } // namespace |
| 191 | Status GeRootModel::Initialize(const ComputeGraphPtr &root_graph) { | 175 | Status GeRootModel::Initialize(const ComputeGraphPtr &root_graph) { |
| 192 | GE_ASSERT_NOTNULL(root_graph); | 176 | GE_ASSERT_NOTNULL(root_graph); |
| @@ -425,11 +409,6 @@ Status GeRootModel::CheckAndSetCustomOpSo() { | |||
| 425 | continue; | 409 | continue; |
| 426 | } | 410 | } |
| 427 | 411 | ||
| 428 | - if (IsEmbeddedHostCpuFusionSo(root_graph_, op_type)) { | ||
| 429 | - GELOGI("[CustomOp] op[%s] uses embedded HostCPU fusion SO, skip path collect.", op_type.c_str()); | ||
| 430 | - continue; | ||
| 431 | - } | ||
| 432 | - | ||
| 433 | std::string so_path; | 412 | std::string so_path; |
| 434 | GE_ASSERT_SUCCESS(ResolvePortableOpSoPath(op_type, portable_op, so_path), | 413 | GE_ASSERT_SUCCESS(ResolvePortableOpSoPath(op_type, portable_op, so_path), |
| 435 | "Resolve custom op so path failed for op[%s].", op_type.c_str()); | 414 | "Resolve custom op so path failed for op[%s].", op_type.c_str()); |
| @@ -446,20 +425,7 @@ Status GeRootModel::CheckAndSetCustomOpSo() { | |||
| 446 | if (!custom_op_so_set_.empty()) { | 425 | if (!custom_op_so_set_.empty()) { |
| 447 | OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_); | 426 | OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_); |
| 448 | } | 427 | } |
| 449 | - size_t embedded_custom_so_num = 0U; | 428 | + GELOGI("[CustomOp]The num of so is %zu.", custom_op_so_set_.size()); |
| 450 | - const auto so_buffer = root_graph_->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer"); | ||
| 451 | - if (so_buffer != nullptr) { | ||
| 452 | - for (const auto &entry : *so_buffer) { | ||
| 453 | - if ((entry.second != nullptr) && (entry.second->GetSoBinType() == SoBinType::kCustomOp)) { | ||
| 454 | - ++embedded_custom_so_num; | ||
| 455 | - } | ||
| 456 | - } | ||
| 457 | - } | ||
| 458 | - if (embedded_custom_so_num > 0U) { | ||
| 459 | - OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_); | ||
| 460 | - } | ||
| 461 | - GELOGI("[CustomOp]The num of path-based so is %zu, embedded so is %zu.", custom_op_so_set_.size(), | ||
| 462 | - embedded_custom_so_num); | ||
| 463 | return SUCCESS; | 429 | return SUCCESS; |
| 464 | } | 430 | } |
| 465 | 431 | ||
| @@ -25,7 +25,7 @@ namespace { | |||
| 25 | const std::string kConstantFoldingName = "libconstant_folding_ops.so"; | 25 | const std::string kConstantFoldingName = "libconstant_folding_ops.so"; |
| 26 | const std::string kOpsHostCpuName = "libops_host_cpu.so"; | 26 | const std::string kOpsHostCpuName = "libops_host_cpu.so"; |
| 27 | const std::string kAicpuConstFoldingName = "libaicpu_const_folding.so"; | 27 | const std::string kAicpuConstFoldingName = "libaicpu_const_folding.so"; |
| 28 | -constexpr char kAicpuHostFindFunc[] = "AicpuHostFindFunc"; | 28 | +const char *const kIsFusedCpuKernelSupported = "IsCpuConstantFoldingFusedOpSupported"; |
| 29 | 29 | ||
| 30 | Status GetDataNumber(const GeTensorDesc &out_desc, uint64_t &data_num) { | 30 | Status GetDataNumber(const GeTensorDesc &out_desc, uint64_t &data_num) { |
| 31 | int64_t num_size = out_desc.GetShape().IsScalar() ? 1 : out_desc.GetShape().GetShapeSize(); | 31 | int64_t num_size = out_desc.GetShape().IsScalar() ? 1 : out_desc.GetShape().GetShapeSize(); |
| @@ -141,13 +141,15 @@ void HostCpuEngine::Finalize() const { | |||
| 141 | GELOGI("start HostCpuEngine::Finalize"); | 141 | GELOGI("start HostCpuEngine::Finalize"); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | -bool HostCpuEngine::IsHostKernelSupported(const std::string &op_type) const { | 144 | +bool HostCpuEngine::IsFusedCpuKernelSupported(const std::string &op_type) const { |
| 145 | - if (host_kernel_finder_ == nullptr) { | 145 | + if (is_fused_cpu_kernel_supported_ == nullptr) { |
| 146 | - GELOGD("HostCPU Gert HostKernel finder is unavailable for op[%s].", op_type.c_str()); | 146 | + GELOGD("HostCPU fused-kernel support query is unavailable for op[%s].", op_type.c_str()); |
| 147 | return false; | 147 | return false; |
| 148 | } | 148 | } |
| 149 | - const bool supported = host_kernel_finder_(op_type) != nullptr; | 149 | + const bool supported = is_fused_cpu_kernel_supported_(op_type.c_str()) == 1; |
| 150 | - GELOGD("HostCPU Gert HostKernel query: op[%s], supported[%d].", op_type.c_str(), static_cast<int32_t>(supported)); | 150 | + if (!supported) { |
| 151 | + GELOGD("HostCPU fused-kernel support query rejected op[%s].", op_type.c_str()); | ||
| 152 | + } | ||
| 151 | return supported; | 153 | return supported; |
| 152 | } | 154 | } |
| 153 | 155 | ||
| @@ -306,11 +308,14 @@ Status HostCpuEngine::LoadLib(const std::string &lib_path, bool invoke_init) { | |||
| 306 | GELOGI("Lib: %s has been opened", lib_path.c_str()); | 308 | GELOGI("Lib: %s has been opened", lib_path.c_str()); |
| 307 | if (lib_path.find(kConstantFoldingName) != lib_path.npos) { | 309 | if (lib_path.find(kConstantFoldingName) != lib_path.npos) { |
| 308 | constant_folding_handle_ = handle; | 310 | constant_folding_handle_ = handle; |
| 309 | - host_kernel_finder_ = reinterpret_cast<HostKernelFinder>(mmDlsym(handle, kAicpuHostFindFunc)); | 311 | + } |
| 310 | - if (host_kernel_finder_ == nullptr) { | 312 | + if (lib_path.find(kAicpuConstFoldingName) != lib_path.npos) { |
| 313 | + is_fused_cpu_kernel_supported_ = | ||
| 314 | + reinterpret_cast<int32_t (*)(const char *)>(mmDlsym(handle, kIsFusedCpuKernelSupported)); | ||
| 315 | + if (is_fused_cpu_kernel_supported_ == nullptr) { | ||
| 311 | const char_t *reason = mmDlerror(); | 316 | const char_t *reason = mmDlerror(); |
| 312 | reason = (reason == nullptr) ? "" : reason; | 317 | reason = (reason == nullptr) ? "" : reason; |
| 313 | - GELOGW("Gert HostKernel finder is unavailable in lib: %s, reason = %s", lib_path.c_str(), reason); | 318 | + GELOGW("Fused HostCPU support query symbol is unavailable in lib: %s, reason = %s", lib_path.c_str(), reason); |
| 314 | } | 319 | } |
| 315 | } | 320 | } |
| 316 | (void)lib_handles_.emplace_back(handle); | 321 | (void)lib_handles_.emplace_back(handle); |
| @@ -19,10 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -namespace gert { | ||
| 23 | -class KernelContext; | ||
| 24 | -} | ||
| 25 | - | ||
| 26 | namespace ge { | 22 | namespace ge { |
| 27 | class HostCpuEngine { | 23 | class HostCpuEngine { |
| 28 | public: | 24 | public: |
| @@ -41,13 +37,9 @@ class HostCpuEngine { | |||
| 41 | return constant_folding_handle_; | 37 | return constant_folding_handle_; |
| 42 | } | 38 | } |
| 43 | 39 | ||
| 44 | - // 查询 libconstant_folding_ops.so 的 Gert HostKernel 路由。只要 op_type 能找到函数即可参与融合。 | 40 | + bool IsFusedCpuKernelSupported(const std::string &op_type) const; |
| 45 | - bool IsHostKernelSupported(const std::string &op_type) const; | ||
| 46 | 41 | ||
| 47 | private: | 42 | private: |
| 48 | - using HostKernelFunc = graphStatus (*)(gert::KernelContext *); | ||
| 49 | - using HostKernelFinder = HostKernelFunc (*)(std::string); | ||
| 50 | - | ||
| 51 | HostCpuEngine() = default; | 43 | HostCpuEngine() = default; |
| 52 | 44 | ||
| 53 | void *DlopenLib(const std::string &lib_path) const; | 45 | void *DlopenLib(const std::string &lib_path) const; |
| @@ -71,7 +63,7 @@ class HostCpuEngine { | |||
| 71 | std::mutex mu_; | 63 | std::mutex mu_; |
| 72 | std::vector<void *> lib_handles_; | 64 | std::vector<void *> lib_handles_; |
| 73 | void *constant_folding_handle_ = nullptr; | 65 | void *constant_folding_handle_ = nullptr; |
| 74 | - HostKernelFinder host_kernel_finder_ = nullptr; | 66 | + int32_t (*is_fused_cpu_kernel_supported_)(const char *) = nullptr; |
| 75 | bool initialized_ = false; | 67 | bool initialized_ = false; |
| 76 | }; | 68 | }; |
| 77 | } // namespace ge | 69 | } // namespace ge |
| @@ -18,7 +18,11 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 21 | 24 | ||
| 25 | + | ||
| 22 | 26 | ||
| 23 | 27 | ||
| 24 | 28 | ||
| @@ -54,6 +58,8 @@ const char *const kExcludedConstantFoldingSo = "libconstant_folding_ops.so"; | |||
| 54 | const char *const kSymGetAllRegisteredOpTypesV2 = "GetAllRegisteredOpTypesV2"; | 58 | const char *const kSymGetAllRegisteredOpTypesV2 = "GetAllRegisteredOpTypesV2"; |
| 55 | const char *const kSymIsRegisteredV2 = "IsRegisteredV2"; | 59 | const char *const kSymIsRegisteredV2 = "IsRegisteredV2"; |
| 56 | const char *const kSymRunCpuKernelV2 = "RunCpuKernelV2"; | 60 | const char *const kSymRunCpuKernelV2 = "RunCpuKernelV2"; |
| 61 | +constexpr uint32_t kFusedHostCpuShapeChanged = 1U; | ||
| 62 | +constexpr uint32_t kFusedHostCpuDataChanged = 2U; | ||
| 57 | 63 | ||
| 58 | using AttrValueMap = google::protobuf::Map<string, aicpuops::AttrValue>; | 64 | using AttrValueMap = google::protobuf::Map<string, aicpuops::AttrValue>; |
| 59 | 65 | ||
| @@ -69,7 +75,62 @@ struct V2ModuleBinding { | |||
| 69 | std::string so_name; | 75 | std::string so_name; |
| 70 | }; | 76 | }; |
| 71 | 77 | ||
| 78 | +struct FusedTensorBindingState { | ||
| 79 | + ge::DataType data_type = ge::DT_UNDEFINED; | ||
| 80 | + ge::Format format = ge::FORMAT_RESERVED; | ||
| 81 | + const void *data = nullptr; | ||
| 82 | + size_t data_size = 0U; | ||
| 83 | + std::vector<int64_t> dims; | ||
| 84 | + bool initialized = false; | ||
| 85 | +}; | ||
| 86 | + | ||
| 87 | +struct FusedCpuKernelPlan { | ||
| 88 | + std::unique_ptr<aicpuops::NodeDef> node_def; | ||
| 89 | + std::unique_ptr<aicpu::CpuKernelContext> context; | ||
| 90 | + const V2ModuleBinding *v2_binding = nullptr; | ||
| 91 | + std::shared_ptr<aicpu::CpuKernel> v1_kernel; | ||
| 92 | + std::vector<aicpu::Tensor *> input_tensors; | ||
| 93 | + std::vector<aicpu::Tensor *> output_tensors; | ||
| 94 | + std::vector<FusedTensorBindingState> input_states; | ||
| 95 | + std::vector<FusedTensorBindingState> output_states; | ||
| 96 | +}; | ||
| 97 | + | ||
| 98 | +struct FusedCpuKernelChainNodeDesc { | ||
| 99 | + const ge::Operator *op; | ||
| 100 | + const ge::Tensor *const *inputs; | ||
| 101 | + size_t input_num; | ||
| 102 | + ge::Tensor *const *outputs; | ||
| 103 | + size_t output_num; | ||
| 104 | + const int32_t *input_binding_indices; | ||
| 105 | + const int32_t *output_binding_indices; | ||
| 106 | +}; | ||
| 107 | + | ||
| 108 | +struct FusedHostCpuTensorBinding { | ||
| 109 | + const int64_t *dims; | ||
| 110 | + uint8_t *data; | ||
| 111 | + size_t dim_num; | ||
| 112 | + size_t data_size; | ||
| 113 | + uint32_t flags; | ||
| 114 | +}; | ||
| 115 | + | ||
| 116 | +struct FusedCpuKernelBinding { | ||
| 117 | + const ge::Tensor *source; | ||
| 118 | + aicpu::Tensor *target; | ||
| 119 | + FusedTensorBindingState *state; | ||
| 120 | + size_t binding_index; | ||
| 121 | +}; | ||
| 122 | + | ||
| 123 | +struct FusedCpuKernelChainNode { | ||
| 124 | + FusedCpuKernelPlan plan; | ||
| 125 | +}; | ||
| 126 | + | ||
| 127 | +struct FusedCpuKernelChainPlan { | ||
| 128 | + std::vector<FusedCpuKernelChainNode> nodes; | ||
| 129 | + std::vector<FusedCpuKernelBinding> bindings; | ||
| 130 | +}; | ||
| 131 | + | ||
| 72 | std::vector<V2ModuleBinding> g_v2_bindings; | 132 | std::vector<V2ModuleBinding> g_v2_bindings; |
| 133 | +std::unordered_set<std::string> g_v1_op_types; | ||
| 73 | // op_type->binding反向索引, Init阶段一次性构建, 运行期只读。 | 134 | // op_type->binding反向索引, Init阶段一次性构建, 运行期只读。 |
| 74 | std::unordered_map<std::string, const V2ModuleBinding *> g_v2_op_index; | 135 | std::unordered_map<std::string, const V2ModuleBinding *> g_v2_op_index; |
| 75 | 136 | ||
| @@ -95,6 +156,27 @@ void ConvertGeToAicpuTensor(const ge::GeTensorDesc &tensor_desc, const std::stri | |||
| 95 | static_cast<int>(tensor_desc.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize()); | 156 | static_cast<int>(tensor_desc.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize()); |
| 96 | } | 157 | } |
| 97 | 158 | ||
| 159 | +void ConvertFusedGeToAicpuTensor(const std::string &tensor_name, const ge::Tensor &ge_tensor, | ||
| 160 | + aicpuops::Tensor *aicpu_tensor) { | ||
| 161 | + aicpu_tensor->set_name(tensor_name); | ||
| 162 | + aicpu_tensor->set_tensor_type(ge_tensor.GetDataType()); | ||
| 163 | + aicpu_tensor->set_data_ptr(static_cast<uint64_t>(reinterpret_cast<intptr_t>(ge_tensor.GetData()))); | ||
| 164 | + aicpu_tensor->set_data_size(static_cast<uint64_t>(ge_tensor.GetSize())); | ||
| 165 | + auto shape = aicpu_tensor->mutable_tensor_shape(); | ||
| 166 | + if (shape != nullptr) { | ||
| 167 | + shape->clear_dim(); | ||
| 168 | + for (size_t i = 0U; i < ge_tensor.GetShapeDimNum(); ++i) { | ||
| 169 | + aicpuops::TensorShape_Dim *aicpu_dim = shape->add_dim(); | ||
| 170 | + if (aicpu_dim != nullptr) { | ||
| 171 | + aicpu_dim->set_size(ge_tensor.GetShapeDim(i)); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + shape->set_data_format(ge_tensor.GetFormat()); | ||
| 175 | + } | ||
| 176 | + AICPUE_LOGI("Op set fused tensor[%s], tensor info[type:%d, data:%p, size:%llu].", tensor_name.c_str(), | ||
| 177 | + static_cast<int>(ge_tensor.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize()); | ||
| 178 | +} | ||
| 179 | + | ||
| 98 | int32_t AddStringAttrToNodeDef(const ge::Operator &op, const char *name, [[maybe_unused]] aicpuops::NodeDef node_def, | 180 | int32_t AddStringAttrToNodeDef(const ge::Operator &op, const char *name, [[maybe_unused]] aicpuops::NodeDef node_def, |
| 99 | aicpuops::AttrValue &attr_value) { | 181 | aicpuops::AttrValue &attr_value) { |
| 100 | std::string s; | 182 | std::string s; |
| @@ -526,6 +608,8 @@ __attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::Hos | |||
| 526 | 608 | ||
| 527 | std::vector<std::string> ops = aicpu::CpuKernelRegister::Instance().GetAllRegisteredOpTypes(); | 609 | std::vector<std::string> ops = aicpu::CpuKernelRegister::Instance().GetAllRegisteredOpTypes(); |
| 528 | AICPUE_LOGI("Registered V1 ops: %llu", static_cast<uint64_t>(ops.size())); | 610 | AICPUE_LOGI("Registered V1 ops: %llu", static_cast<uint64_t>(ops.size())); |
| 611 | + g_v1_op_types.clear(); | ||
| 612 | + g_v1_op_types.insert(ops.cbegin(), ops.cend()); | ||
| 529 | RegisterHostCpuOp(ops, create_fn); | 613 | RegisterHostCpuOp(ops, create_fn); |
| 530 | 614 | ||
| 531 | // 枚举每个ops so的V2算子, 同时构建op_type->binding反向索引。 | 615 | // 枚举每个ops so的V2算子, 同时构建op_type->binding反向索引。 |
| @@ -572,7 +656,7 @@ int32_t BuildInputTensors(const ge::OpDescPtr &op_desc, const std::map<std::stri | |||
| 572 | return 0; | 656 | return 0; |
| 573 | } | 657 | } |
| 574 | 658 | ||
| 575 | -int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, std::map<std::string, ge::Tensor> &outputs, | 659 | +int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, const std::map<std::string, ge::Tensor> &outputs, |
| 576 | const char *op_type, aicpuops::NodeDef &node_def) { | 660 | const char *op_type, aicpuops::NodeDef &node_def) { |
| 577 | uint32_t count = static_cast<uint32_t>(op_desc->GetOutputsSize()); | 661 | uint32_t count = static_cast<uint32_t>(op_desc->GetOutputsSize()); |
| 578 | for (uint32_t i = 0; i < count; ++i) { | 662 | for (uint32_t i = 0; i < count; ++i) { |
| @@ -592,6 +676,55 @@ int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, std::map<std::string, g | |||
| 592 | return 0; | 676 | return 0; |
| 593 | } | 677 | } |
| 594 | 678 | ||
| 679 | +int32_t BuildFusedInputTensorArray(const ge::OpDescPtr &op_desc, const ge::Tensor *const *inputs, | ||
| 680 | + const size_t input_num, aicpuops::NodeDef &node_def) { | ||
| 681 | + const size_t count = op_desc->GetAllInputsSize(); | ||
| 682 | + if ((count != input_num) || ((count != 0U) && (inputs == nullptr))) { | ||
| 683 | + AICPUE_LOGE("Invalid fused input tensor array: op[%s], expected_num[%zu], actual_num[%zu], inputs_null[%d].", | ||
| 684 | + AICPUE_ERROR_CODE, op_desc->GetTypePtr(), count, input_num, static_cast<int32_t>(inputs == nullptr)); | ||
| 685 | + return -1; | ||
| 686 | + } | ||
| 687 | + for (size_t i = 0U; i < count; ++i) { | ||
| 688 | + if (inputs[i] == nullptr) { | ||
| 689 | + AICPUE_LOGE("Fused input tensor is null: op[%s], input_index[%zu].", AICPUE_ERROR_CODE, op_desc->GetTypePtr(), i); | ||
| 690 | + return -1; | ||
| 691 | + } | ||
| 692 | + aicpuops::Tensor *tensor = node_def.add_inputs(); | ||
| 693 | + if (tensor == nullptr) { | ||
| 694 | + AICPUE_LOGE("Failed to add fused input tensor to NodeDef: op[%s], input_index[%zu].", AICPUE_ERROR_CODE, | ||
| 695 | + op_desc->GetTypePtr(), i); | ||
| 696 | + return -1; | ||
| 697 | + } | ||
| 698 | + ConvertFusedGeToAicpuTensor(op_desc->GetInputNameByIndex(static_cast<uint32_t>(i)), *inputs[i], tensor); | ||
| 699 | + } | ||
| 700 | + return 0; | ||
| 701 | +} | ||
| 702 | + | ||
| 703 | +int32_t BuildFusedOutputTensorArray(const ge::OpDescPtr &op_desc, ge::Tensor *const *outputs, const size_t output_num, | ||
| 704 | + aicpuops::NodeDef &node_def) { | ||
| 705 | + const size_t count = op_desc->GetOutputsSize(); | ||
| 706 | + if ((count != output_num) || ((count != 0U) && (outputs == nullptr))) { | ||
| 707 | + AICPUE_LOGE("Invalid fused output tensor array: op[%s], expected_num[%zu], actual_num[%zu], outputs_null[%d].", | ||
| 708 | + AICPUE_ERROR_CODE, op_desc->GetTypePtr(), count, output_num, static_cast<int32_t>(outputs == nullptr)); | ||
| 709 | + return -1; | ||
| 710 | + } | ||
| 711 | + for (size_t i = 0U; i < count; ++i) { | ||
| 712 | + if (outputs[i] == nullptr) { | ||
| 713 | + AICPUE_LOGE("Fused output tensor is null: op[%s], output_index[%zu].", AICPUE_ERROR_CODE, op_desc->GetTypePtr(), | ||
| 714 | + i); | ||
| 715 | + return -1; | ||
| 716 | + } | ||
| 717 | + aicpuops::Tensor *tensor = node_def.add_outputs(); | ||
| 718 | + if (tensor == nullptr) { | ||
| 719 | + AICPUE_LOGE("Failed to add fused output tensor to NodeDef: op[%s], output_index[%zu].", AICPUE_ERROR_CODE, | ||
| 720 | + op_desc->GetTypePtr(), i); | ||
| 721 | + return -1; | ||
| 722 | + } | ||
| 723 | + ConvertFusedGeToAicpuTensor(op_desc->GetOutputNameByIndex(static_cast<uint32_t>(i)), *outputs[i], tensor); | ||
| 724 | + } | ||
| 725 | + return 0; | ||
| 726 | +} | ||
| 727 | + | ||
| 595 | int32_t BuildNodeDefAttrs(const ge::Operator &op, aicpuops::NodeDef &node_def) { | 728 | int32_t BuildNodeDefAttrs(const ge::Operator &op, aicpuops::NodeDef &node_def) { |
| 596 | std::map<ge::AscendString, ge::AscendString> attrs; | 729 | std::map<ge::AscendString, ge::AscendString> attrs; |
| 597 | if (op.GetAllAttrNamesAndTypes(attrs) != ge::GRAPH_SUCCESS) { | 730 | if (op.GetAllAttrNamesAndTypes(attrs) != ge::GRAPH_SUCCESS) { |
| @@ -637,6 +770,277 @@ int32_t BuildNodeDef(const ge::Operator &op, const std::string &op_type_str, | |||
| 637 | return BuildNodeDefAttrs(op, node_def); | 770 | return BuildNodeDefAttrs(op, node_def); |
| 638 | } | 771 | } |
| 639 | 772 | ||
| 773 | +int32_t BuildFusedNodeDefFromTensorArray(const ge::Operator &op, const std::string &op_type_str, | ||
| 774 | + const ge::Tensor *const *inputs, const size_t input_num, | ||
| 775 | + ge::Tensor *const *outputs, const size_t output_num, | ||
| 776 | + aicpuops::NodeDef &node_def) { | ||
| 777 | + const ge::OpDescPtr op_desc = ge::OpDescUtils::GetOpDescFromOperator(op); | ||
| 778 | + if (op_desc == nullptr) { | ||
| 779 | + AICPUE_LOGW("Op[%s] get op desc failed.", op_type_str.c_str()); | ||
| 780 | + return -1; | ||
| 781 | + } | ||
| 782 | + node_def.set_op(op_type_str); | ||
| 783 | + int32_t ret = BuildFusedInputTensorArray(op_desc, inputs, input_num, node_def); | ||
| 784 | + if (ret != 0) { | ||
| 785 | + return ret; | ||
| 786 | + } | ||
| 787 | + ret = BuildFusedOutputTensorArray(op_desc, outputs, output_num, node_def); | ||
| 788 | + if (ret != 0) { | ||
| 789 | + return ret; | ||
| 790 | + } | ||
| 791 | + return BuildNodeDefAttrs(op, node_def); | ||
| 792 | +} | ||
| 793 | + | ||
| 794 | +bool HasSameShape(const ge::Tensor &source, const FusedTensorBindingState &state) { | ||
| 795 | + const size_t dim_num = source.GetShapeDimNum(); | ||
| 796 | + if (state.dims.size() != dim_num) { | ||
| 797 | + return false; | ||
| 798 | + } | ||
| 799 | + for (size_t i = 0U; i < dim_num; ++i) { | ||
| 800 | + if (state.dims[i] != source.GetShapeDim(i)) { | ||
| 801 | + return false; | ||
| 802 | + } | ||
| 803 | + } | ||
| 804 | + return true; | ||
| 805 | +} | ||
| 806 | + | ||
| 807 | +int32_t InitializeFusedTensor(const ge::Tensor &source, aicpu::Tensor *target, FusedTensorBindingState &state) { | ||
| 808 | + const void *data = static_cast<const void *>(source.GetData()); | ||
| 809 | + const size_t data_size = source.GetSize(); | ||
| 810 | + target->SetData(const_cast<void *>(data)); | ||
| 811 | + target->SetDataSize(static_cast<uint64_t>(data_size)); | ||
| 812 | + target->SetDataType(static_cast<aicpu::DataType>(source.GetDataType())); | ||
| 813 | + | ||
| 814 | + const std::shared_ptr<aicpu::TensorShape> tensor_shape = target->GetTensorShape(); | ||
| 815 | + if (tensor_shape == nullptr) { | ||
| 816 | + AICPUE_LOGE("Failed to get target TensorShape while initializing fused Tensor.", AICPUE_ERROR_CODE); | ||
| 817 | + return -1; | ||
| 818 | + } | ||
| 819 | + state.dims.resize(source.GetShapeDimNum()); | ||
| 820 | + for (size_t i = 0U; i < state.dims.size(); ++i) { | ||
| 821 | + state.dims[i] = source.GetShapeDim(i); | ||
| 822 | + } | ||
| 823 | + tensor_shape->SetDimSizes(state.dims); | ||
| 824 | + const ge::Format format = source.GetFormat(); | ||
| 825 | + tensor_shape->SetFormat(static_cast<aicpu::Format>(format)); | ||
| 826 | + | ||
| 827 | + state.data = data; | ||
| 828 | + state.data_size = data_size; | ||
| 829 | + state.data_type = source.GetDataType(); | ||
| 830 | + state.format = format; | ||
| 831 | + state.initialized = true; | ||
| 832 | + return 0; | ||
| 833 | +} | ||
| 834 | + | ||
| 835 | +int32_t RebindFusedTensor(const ge::Tensor &source, aicpu::Tensor *target, FusedTensorBindingState &state) { | ||
| 836 | + if ((target == nullptr) || ((source.GetSize() != 0U) && (source.GetData() == nullptr))) { | ||
| 837 | + AICPUE_LOGE("Failed to rebind fused Tensor: target_null[%d], data_null[%d], data_size[%zu].", AICPUE_ERROR_CODE, | ||
| 838 | + static_cast<int32_t>(target == nullptr), | ||
| 839 | + static_cast<int32_t>((source.GetSize() != 0U) && (source.GetData() == nullptr)), source.GetSize()); | ||
| 840 | + return -1; | ||
| 841 | + } | ||
| 842 | + if (!state.initialized) { | ||
| 843 | + return InitializeFusedTensor(source, target, state); | ||
| 844 | + } | ||
| 845 | + const void *data = static_cast<const void *>(source.GetData()); | ||
| 846 | + const size_t data_size = source.GetSize(); | ||
| 847 | + if (state.data != data) { | ||
| 848 | + target->SetData(const_cast<void *>(data)); | ||
| 849 | + state.data = data; | ||
| 850 | + } | ||
| 851 | + if (state.data_size != data_size) { | ||
| 852 | + target->SetDataSize(static_cast<uint64_t>(data_size)); | ||
| 853 | + state.data_size = data_size; | ||
| 854 | + } | ||
| 855 | + | ||
| 856 | + const ge::DataType data_type = source.GetDataType(); | ||
| 857 | + if (state.data_type != data_type) { | ||
| 858 | + target->SetDataType(static_cast<aicpu::DataType>(data_type)); | ||
| 859 | + state.data_type = data_type; | ||
| 860 | + } | ||
| 861 | + | ||
| 862 | + const ge::Format format = source.GetFormat(); | ||
| 863 | + const bool shape_changed = !HasSameShape(source, state); | ||
| 864 | + if (shape_changed || (state.format != format)) { | ||
| 865 | + const std::shared_ptr<aicpu::TensorShape> tensor_shape = target->GetTensorShape(); | ||
| 866 | + if (tensor_shape == nullptr) { | ||
| 867 | + AICPUE_LOGE("Failed to get target TensorShape while rebinding fused Tensor.", AICPUE_ERROR_CODE); | ||
| 868 | + return -1; | ||
| 869 | + } | ||
| 870 | + if (shape_changed) { | ||
| 871 | + state.dims.resize(source.GetShapeDimNum()); | ||
| 872 | + for (size_t i = 0U; i < state.dims.size(); ++i) { | ||
| 873 | + state.dims[i] = source.GetShapeDim(i); | ||
| 874 | + } | ||
| 875 | + tensor_shape->SetDimSizes(state.dims); | ||
| 876 | + } | ||
| 877 | + tensor_shape->SetFormat(static_cast<aicpu::Format>(format)); | ||
| 878 | + state.format = format; | ||
| 879 | + } | ||
| 880 | + state.initialized = true; | ||
| 881 | + return 0; | ||
| 882 | +} | ||
| 883 | + | ||
| 884 | +int32_t RebindFusedTensorDataByFlags(const ge::Tensor &source, aicpu::Tensor *target, FusedTensorBindingState &state, | ||
| 885 | + const uint32_t binding_flags) { | ||
| 886 | + if ((binding_flags & kFusedHostCpuDataChanged) == 0U) { | ||
| 887 | + return 0; | ||
| 888 | + } | ||
| 889 | + const void *data = static_cast<const void *>(source.GetData()); | ||
| 890 | + const size_t data_size = source.GetSize(); | ||
| 891 | + if ((data_size != 0U) && (data == nullptr)) { | ||
| 892 | + AICPUE_LOGE("Failed to rebind fused Tensor data by flags: data is null, data_size[%zu], binding_flags[%u].", | ||
| 893 | + AICPUE_ERROR_CODE, data_size, binding_flags); | ||
| 894 | + return -1; | ||
| 895 | + } | ||
| 896 | + if (state.data != data) { | ||
| 897 | + target->SetData(const_cast<void *>(data)); | ||
| 898 | + state.data = data; | ||
| 899 | + } | ||
| 900 | + if (state.data_size != data_size) { | ||
| 901 | + target->SetDataSize(static_cast<uint64_t>(data_size)); | ||
| 902 | + state.data_size = data_size; | ||
| 903 | + } | ||
| 904 | + return 0; | ||
| 905 | +} | ||
| 906 | + | ||
| 907 | +int32_t RebindFusedTensorShapeByFlags(const ge::Tensor &source, aicpu::Tensor *target, FusedTensorBindingState &state, | ||
| 908 | + const uint32_t binding_flags) { | ||
| 909 | + if ((binding_flags & kFusedHostCpuShapeChanged) == 0U) { | ||
| 910 | + return 0; | ||
| 911 | + } | ||
| 912 | + const ge::DataType data_type = source.GetDataType(); | ||
| 913 | + if (state.data_type != data_type) { | ||
| 914 | + target->SetDataType(static_cast<aicpu::DataType>(data_type)); | ||
| 915 | + state.data_type = data_type; | ||
| 916 | + } | ||
| 917 | + | ||
| 918 | + const ge::Format format = source.GetFormat(); | ||
| 919 | + const bool shape_changed = !HasSameShape(source, state); | ||
| 920 | + if (shape_changed || (state.format != format)) { | ||
| 921 | + const std::shared_ptr<aicpu::TensorShape> tensor_shape = target->GetTensorShape(); | ||
| 922 | + if (tensor_shape == nullptr) { | ||
| 923 | + AICPUE_LOGE("Failed to get target TensorShape while rebinding fused Tensor by flags: binding_flags[%u].", | ||
| 924 | + AICPUE_ERROR_CODE, binding_flags); | ||
| 925 | + return -1; | ||
| 926 | + } | ||
| 927 | + if (shape_changed) { | ||
| 928 | + state.dims.resize(source.GetShapeDimNum()); | ||
| 929 | + for (size_t i = 0U; i < state.dims.size(); ++i) { | ||
| 930 | + state.dims[i] = source.GetShapeDim(i); | ||
| 931 | + } | ||
| 932 | + tensor_shape->SetDimSizes(state.dims); | ||
| 933 | + } | ||
| 934 | + tensor_shape->SetFormat(static_cast<aicpu::Format>(format)); | ||
| 935 | + state.format = format; | ||
| 936 | + } | ||
| 937 | + return 0; | ||
| 938 | +} | ||
| 939 | + | ||
| 940 | +int32_t RebindFusedTensorByFlags(const ge::Tensor &source, aicpu::Tensor *target, FusedTensorBindingState &state, | ||
| 941 | + uint32_t binding_flags) { | ||
| 942 | + if (target == nullptr) { | ||
| 943 | + AICPUE_LOGE("Failed to rebind fused Tensor by flags: target is null, binding_flags[%u].", AICPUE_ERROR_CODE, | ||
| 944 | + binding_flags); | ||
| 945 | + return -1; | ||
| 946 | + } | ||
| 947 | + if (!state.initialized) { | ||
| 948 | + return RebindFusedTensor(source, target, state); | ||
| 949 | + } | ||
| 950 | + if ((RebindFusedTensorDataByFlags(source, target, state, binding_flags) != 0) || | ||
| 951 | + (RebindFusedTensorShapeByFlags(source, target, state, binding_flags) != 0)) { | ||
| 952 | + return -1; | ||
| 953 | + } | ||
| 954 | + state.initialized = true; | ||
| 955 | + return 0; | ||
| 956 | +} | ||
| 957 | + | ||
| 958 | +int32_t RebindFusedTensorByBinding(const FusedHostCpuTensorBinding &binding, aicpu::Tensor *target, | ||
| 959 | + FusedTensorBindingState &state) { | ||
| 960 | + if ((target == nullptr) || ((binding.dim_num != 0U) && (binding.dims == nullptr)) || | ||
| 961 | + ((binding.data_size != 0U) && (binding.data == nullptr))) { | ||
| 962 | + AICPUE_LOGE( | ||
| 963 | + "Invalid fused Tensor binding: target_null[%d], dim_num[%zu], dims_null[%d], data_size[%zu], " | ||
| 964 | + "data_null[%d], flags[%u].", | ||
| 965 | + AICPUE_ERROR_CODE, static_cast<int32_t>(target == nullptr), binding.dim_num, | ||
| 966 | + static_cast<int32_t>((binding.dim_num != 0U) && (binding.dims == nullptr)), binding.data_size, | ||
| 967 | + static_cast<int32_t>((binding.data_size != 0U) && (binding.data == nullptr)), binding.flags); | ||
| 968 | + return -1; | ||
| 969 | + } | ||
| 970 | + uint32_t binding_flags = binding.flags; | ||
| 971 | + if (!state.initialized) { | ||
| 972 | + binding_flags |= kFusedHostCpuShapeChanged | kFusedHostCpuDataChanged; | ||
| 973 | + } | ||
| 974 | + if ((binding_flags & kFusedHostCpuDataChanged) != 0U) { | ||
| 975 | + target->SetData(binding.data); | ||
| 976 | + target->SetDataSize(static_cast<uint64_t>(binding.data_size)); | ||
| 977 | + state.data = binding.data; | ||
| 978 | + state.data_size = binding.data_size; | ||
| 979 | + } | ||
| 980 | + if ((binding_flags & kFusedHostCpuShapeChanged) != 0U) { | ||
| 981 | + const std::shared_ptr<aicpu::TensorShape> tensor_shape = target->GetTensorShape(); | ||
| 982 | + if (tensor_shape == nullptr) { | ||
| 983 | + AICPUE_LOGE("Failed to get target TensorShape from fused binding: dim_num[%zu], flags[%u].", AICPUE_ERROR_CODE, | ||
| 984 | + binding.dim_num, binding.flags); | ||
| 985 | + return -1; | ||
| 986 | + } | ||
| 987 | + state.dims.resize(binding.dim_num); | ||
| 988 | + for (size_t i = 0U; i < binding.dim_num; ++i) { | ||
| 989 | + state.dims[i] = binding.dims[i]; | ||
| 990 | + } | ||
| 991 | + tensor_shape->SetDimSizes(state.dims); | ||
| 992 | + } | ||
| 993 | + state.initialized = true; | ||
| 994 | + return 0; | ||
| 995 | +} | ||
| 996 | + | ||
| 997 | +int32_t RebindFusedPlan(FusedCpuKernelPlan &plan, const ge::Tensor *const *inputs, const size_t input_num, | ||
| 998 | + ge::Tensor *const *outputs, const size_t output_num) { | ||
| 999 | + if ((plan.context == nullptr) || (input_num != plan.input_tensors.size()) || | ||
| 1000 | + (output_num != plan.output_tensors.size()) || ((input_num != 0U) && (inputs == nullptr)) || | ||
| 1001 | + ((output_num != 0U) && (outputs == nullptr))) { | ||
| 1002 | + AICPUE_LOGE( | ||
| 1003 | + "Invalid fused CPU plan binding: context_null[%d], input_num[%zu], expected_inputs[%zu], " | ||
| 1004 | + "output_num[%zu], expected_outputs[%zu], inputs_null[%d], outputs_null[%d].", | ||
| 1005 | + AICPUE_ERROR_CODE, static_cast<int32_t>(plan.context == nullptr), input_num, plan.input_tensors.size(), | ||
| 1006 | + output_num, plan.output_tensors.size(), static_cast<int32_t>(inputs == nullptr), | ||
| 1007 | + static_cast<int32_t>(outputs == nullptr)); | ||
| 1008 | + return -1; | ||
| 1009 | + } | ||
| 1010 | + for (size_t i = 0U; i < input_num; ++i) { | ||
| 1011 | + if ((inputs[i] == nullptr) || (RebindFusedTensor(*inputs[i], plan.input_tensors[i], plan.input_states[i]) != 0)) { | ||
| 1012 | + AICPUE_LOGE("Failed to rebind fused CPU plan input: input_index[%zu], input_null[%d].", AICPUE_ERROR_CODE, i, | ||
| 1013 | + static_cast<int32_t>(inputs[i] == nullptr)); | ||
| 1014 | + return -1; | ||
| 1015 | + } | ||
| 1016 | + } | ||
| 1017 | + for (size_t i = 0U; i < output_num; ++i) { | ||
| 1018 | + if ((outputs[i] == nullptr) || | ||
| 1019 | + (RebindFusedTensor(*outputs[i], plan.output_tensors[i], plan.output_states[i]) != 0)) { | ||
| 1020 | + AICPUE_LOGE("Failed to rebind fused CPU plan output: output_index[%zu], output_null[%d].", AICPUE_ERROR_CODE, i, | ||
| 1021 | + static_cast<int32_t>(outputs[i] == nullptr)); | ||
| 1022 | + return -1; | ||
| 1023 | + } | ||
| 1024 | + } | ||
| 1025 | + return 0; | ||
| 1026 | +} | ||
| 1027 | + | ||
| 1028 | +int32_t RunFusedCpuKernelPlan(FusedCpuKernelPlan &plan) { | ||
| 1029 | + uint32_t ret = 0U; | ||
| 1030 | + if (plan.v2_binding != nullptr) { | ||
| 1031 | + ret = plan.v2_binding->run_cpu_kernel(*plan.context); | ||
| 1032 | + } else if (plan.v1_kernel != nullptr) { | ||
| 1033 | + ret = plan.v1_kernel->Compute(*plan.context); | ||
| 1034 | + } else { | ||
| 1035 | + AICPUE_LOGE("Fused CPU kernel plan has neither V1 kernel nor V2 binding.", AICPUE_ERROR_CODE); | ||
| 1036 | + return -1; | ||
| 1037 | + } | ||
| 1038 | + if (ret != 0U) { | ||
| 1039 | + AICPUE_LOGE("Fused CPU kernel execution failed: ret[%u].", AICPUE_ERROR_CODE, ret); | ||
| 1040 | + } | ||
| 1041 | + return (ret == 0U) ? 0 : -1; | ||
| 1042 | +} | ||
| 1043 | + | ||
| 640 | // 查找op_type对应的V2 binding。未命中返回nullptr表示走V1路径。 | 1044 | // 查找op_type对应的V2 binding。未命中返回nullptr表示走V1路径。 |
| 641 | const V2ModuleBinding *LookupV2Binding(const std::string &op_type) { | 1045 | const V2ModuleBinding *LookupV2Binding(const std::string &op_type) { |
| 642 | auto iter = g_v2_op_index.find(op_type); | 1046 | auto iter = g_v2_op_index.find(op_type); |
| @@ -650,6 +1054,14 @@ const V2ModuleBinding *LookupV2Binding(const std::string &op_type) { | |||
| 650 | return binding; | 1054 | return binding; |
| 651 | } | 1055 | } |
| 652 | 1056 | ||
| 1057 | +__attribute__((visibility("default"))) int32_t IsCpuConstantFoldingFusedOpSupported(const char *op_type) { | ||
| 1058 | + if ((op_type == nullptr) || (op_type[0] == '\0')) { | ||
| 1059 | + return 0; | ||
| 1060 | + } | ||
| 1061 | + const std::string op_type_str(op_type); | ||
| 1062 | + return ((LookupV2Binding(op_type_str) != nullptr) || (g_v1_op_types.count(op_type_str) > 0U)) ? 1 : 0; | ||
| 1063 | +} | ||
| 1064 | + | ||
| 653 | __attribute__((visibility("default"))) int32_t | 1065 | __attribute__((visibility("default"))) int32_t |
| 654 | CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs, | 1066 | CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs, |
| 655 | std::map<std::string, ge::Tensor> outputs) { | 1067 | std::map<std::string, ge::Tensor> outputs) { |
| @@ -697,4 +1109,302 @@ CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, | |||
| 697 | AICPUE_LOGI("Finish cpu op[%s].", op_type.GetString()); | 1109 | AICPUE_LOGI("Finish cpu op[%s].", op_type.GetString()); |
| 698 | return 0; | 1110 | return 0; |
| 699 | } | 1111 | } |
| 1112 | + | ||
| 1113 | +int32_t InitializeFusedCpuKernel(const ge::Operator &op, FusedCpuKernelPlan &plan, std::string &op_type_str, | ||
| 1114 | + ge::AscendString &op_type) { | ||
| 1115 | + if (op.GetOpType(op_type) != ge::GRAPH_SUCCESS) { | ||
| 1116 | + return -1; | ||
| 1117 | + } | ||
| 1118 | + op_type_str = op_type.GetString(); | ||
| 1119 | + plan.v2_binding = LookupV2Binding(op_type_str); | ||
| 1120 | + if (plan.v2_binding == nullptr) { | ||
| 1121 | + plan.v1_kernel = aicpu::CpuKernelRegister::Instance().GetCpuKernel(op_type_str); | ||
| 1122 | + if (plan.v1_kernel == nullptr) { | ||
| 1123 | + AICPUE_LOGW("op type [%s] is not registered in v1 nor v2.", op_type.GetString()); | ||
| 1124 | + return -1; | ||
| 1125 | + } | ||
| 1126 | + } | ||
| 1127 | + return 0; | ||
| 1128 | +} | ||
| 1129 | + | ||
| 1130 | +int32_t AllocateFusedCpuKernelPlan(FusedCpuKernelPlan &plan, const ge::AscendString &op_type) { | ||
| 1131 | + plan.node_def.reset(new (std::nothrow) aicpuops::NodeDef()); | ||
| 1132 | + plan.context.reset(new (std::nothrow) aicpu::CpuKernelContext(aicpu::HOST)); | ||
| 1133 | + if ((plan.node_def == nullptr) || (plan.context == nullptr)) { | ||
| 1134 | + AICPUE_LOGE("Failed to allocate fused CPU kernel plan objects: op[%s], node_def_null[%d], context_null[%d].", | ||
| 1135 | + AICPUE_ERROR_CODE, op_type.GetString(), static_cast<int32_t>(plan.node_def == nullptr), | ||
| 1136 | + static_cast<int32_t>(plan.context == nullptr)); | ||
| 1137 | + return -1; | ||
| 1138 | + } | ||
| 1139 | + return 0; | ||
| 1140 | +} | ||
| 1141 | + | ||
| 1142 | +int32_t InitializeFusedCpuKernelTensors(FusedCpuKernelPlan &plan, const size_t input_num, const size_t output_num, | ||
| 1143 | + const ge::AscendString &op_type) { | ||
| 1144 | + plan.input_tensors.resize(input_num); | ||
| 1145 | + plan.output_tensors.resize(output_num); | ||
| 1146 | + plan.input_states.resize(input_num); | ||
| 1147 | + plan.output_states.resize(output_num); | ||
| 1148 | + for (size_t i = 0U; i < input_num; ++i) { | ||
| 1149 | + plan.input_tensors[i] = plan.context->Input(static_cast<uint32_t>(i)); | ||
| 1150 | + if (plan.input_tensors[i] == nullptr) { | ||
| 1151 | + AICPUE_LOGE("Fused CPU kernel context input is null: op[%s], input_index[%zu], input_num[%zu].", | ||
| 1152 | + AICPUE_ERROR_CODE, op_type.GetString(), i, input_num); | ||
| 1153 | + return -1; | ||
| 1154 | + } | ||
| 1155 | + } | ||
| 1156 | + for (size_t i = 0U; i < output_num; ++i) { | ||
| 1157 | + plan.output_tensors[i] = plan.context->Output(static_cast<uint32_t>(i)); | ||
| 1158 | + if (plan.output_tensors[i] == nullptr) { | ||
| 1159 | + AICPUE_LOGE("Fused CPU kernel context output is null: op[%s], output_index[%zu], output_num[%zu].", | ||
| 1160 | + AICPUE_ERROR_CODE, op_type.GetString(), i, output_num); | ||
| 1161 | + return -1; | ||
| 1162 | + } | ||
| 1163 | + } | ||
| 1164 | + return 0; | ||
| 1165 | +} | ||
| 1166 | + | ||
| 1167 | +int32_t InitializeFusedCpuKernelPlan(const ge::Operator &op, const ge::Tensor *const *inputs, const size_t input_num, | ||
| 1168 | + ge::Tensor *const *outputs, const size_t output_num, FusedCpuKernelPlan &plan) { | ||
| 1169 | + ge::AscendString op_type; | ||
| 1170 | + std::string op_type_str; | ||
| 1171 | + if (InitializeFusedCpuKernel(op, plan, op_type_str, op_type) != 0) { | ||
| 1172 | + return -1; | ||
| 1173 | + } | ||
| 1174 | + if (AllocateFusedCpuKernelPlan(plan, op_type) != 0) { | ||
| 1175 | + return -1; | ||
| 1176 | + } | ||
| 1177 | + if (BuildFusedNodeDefFromTensorArray(op, op_type_str, inputs, input_num, outputs, output_num, *plan.node_def) != 0) { | ||
| 1178 | + AICPUE_LOGE("Failed to build fused CPU NodeDef: op[%s], inputs[%zu], outputs[%zu].", AICPUE_ERROR_CODE, | ||
| 1179 | + op_type.GetString(), input_num, output_num); | ||
| 1180 | + return -1; | ||
| 1181 | + } | ||
| 1182 | + const int32_t context_ret = plan.context->Init(plan.node_def.get()); | ||
| 1183 | + if (context_ret != 0) { | ||
| 1184 | + AICPUE_LOGE("Failed to initialize fused CPU kernel context: op[%s], ret[%d].", AICPUE_ERROR_CODE, | ||
| 1185 | + op_type.GetString(), context_ret); | ||
| 1186 | + return -1; | ||
| 1187 | + } | ||
| 1188 | + if (InitializeFusedCpuKernelTensors(plan, input_num, output_num, op_type) != 0) { | ||
| 1189 | + return -1; | ||
| 1190 | + } | ||
| 1191 | + if (RebindFusedPlan(plan, inputs, input_num, outputs, output_num) != 0) { | ||
| 1192 | + AICPUE_LOGE("Failed to bind fused CPU kernel plan tensors: op[%s], inputs[%zu], outputs[%zu].", AICPUE_ERROR_CODE, | ||
| 1193 | + op_type.GetString(), input_num, output_num); | ||
| 1194 | + return -1; | ||
| 1195 | + } | ||
| 1196 | + AICPUE_LOGD("Created fused cpu execution plan for op[%s], inputs[%zu], outputs[%zu].", op_type.GetString(), input_num, | ||
| 1197 | + output_num); | ||
| 1198 | + return 0; | ||
| 1199 | +} | ||
| 1200 | + | ||
| 1201 | +int32_t CalculateFusedChainBindingCapacity(const FusedCpuKernelChainNodeDesc *descs, const size_t node_num, | ||
| 1202 | + size_t &binding_capacity) { | ||
| 1203 | + binding_capacity = 0U; | ||
| 1204 | + for (size_t i = 0U; i < node_num; ++i) { | ||
| 1205 | + if (descs[i].input_num > (std::numeric_limits<size_t>::max() - descs[i].output_num)) { | ||
| 1206 | + AICPUE_LOGE("Fused CPU chain node binding count overflows size_t: node_index[%zu], inputs[%zu], outputs[%zu].", | ||
| 1207 | + AICPUE_ERROR_CODE, i, descs[i].input_num, descs[i].output_num); | ||
| 1208 | + return -1; | ||
| 1209 | + } | ||
| 1210 | + const size_t node_binding_count = descs[i].input_num + descs[i].output_num; | ||
| 1211 | + if (binding_capacity > (std::numeric_limits<size_t>::max() - node_binding_count)) { | ||
| 1212 | + AICPUE_LOGE( | ||
| 1213 | + "Fused CPU chain binding capacity overflows size_t: node_index[%zu], current_capacity[%zu], " | ||
| 1214 | + "node_binding_count[%zu].", | ||
| 1215 | + AICPUE_ERROR_CODE, i, binding_capacity, node_binding_count); | ||
| 1216 | + return -1; | ||
| 1217 | + } | ||
| 1218 | + binding_capacity += node_binding_count; | ||
| 1219 | + } | ||
| 1220 | + return 0; | ||
| 1221 | +} | ||
| 1222 | + | ||
| 1223 | +int32_t AddFusedChainInputBindings(const FusedCpuKernelChainNodeDesc &desc, const size_t node_index, | ||
| 1224 | + const size_t external_binding_num, FusedCpuKernelChainNode &node, | ||
| 1225 | + FusedCpuKernelChainPlan &chain) { | ||
| 1226 | + for (size_t j = 0U; j < desc.input_num; ++j) { | ||
| 1227 | + const int32_t binding_index = | ||
| 1228 | + (desc.input_binding_indices == nullptr) ? static_cast<int32_t>(j) : desc.input_binding_indices[j]; | ||
| 1229 | + if ((binding_index >= 0) && (static_cast<size_t>(binding_index) < external_binding_num) && | ||
| 1230 | + (desc.inputs[j] != nullptr)) { | ||
| 1231 | + chain.bindings.push_back( | ||
| 1232 | + {desc.inputs[j], node.plan.input_tensors[j], &node.plan.input_states[j], static_cast<size_t>(binding_index)}); | ||
| 1233 | + } else if ((binding_index >= 0) && | ||
| 1234 | + ((desc.inputs[j] == nullptr) || (static_cast<size_t>(binding_index) >= external_binding_num))) { | ||
| 1235 | + AICPUE_LOGE( | ||
| 1236 | + "Invalid fused input binding: node_index[%zu], input_index[%zu], binding_index[%d], " | ||
| 1237 | + "external_binding_num[%zu], input_null[%d].", | ||
| 1238 | + AICPUE_ERROR_CODE, node_index, j, binding_index, external_binding_num, | ||
| 1239 | + static_cast<int32_t>(desc.inputs[j] == nullptr)); | ||
| 1240 | + return -1; | ||
| 1241 | + } | ||
| 1242 | + } | ||
| 1243 | + return 0; | ||
| 1244 | +} | ||
| 1245 | + | ||
| 1246 | +int32_t AddFusedChainOutputBindings(const FusedCpuKernelChainNodeDesc &desc, const size_t node_index, | ||
| 1247 | + const size_t external_binding_num, FusedCpuKernelChainNode &node, | ||
| 1248 | + FusedCpuKernelChainPlan &chain) { | ||
| 1249 | + for (size_t j = 0U; j < desc.output_num; ++j) { | ||
| 1250 | + const int32_t binding_index = | ||
| 1251 | + (desc.output_binding_indices == nullptr) ? static_cast<int32_t>(j) : desc.output_binding_indices[j]; | ||
| 1252 | + if ((binding_index >= 0) && (static_cast<size_t>(binding_index) < external_binding_num) && | ||
| 1253 | + (desc.outputs[j] != nullptr)) { | ||
| 1254 | + chain.bindings.push_back({desc.outputs[j], node.plan.output_tensors[j], &node.plan.output_states[j], | ||
| 1255 | + static_cast<size_t>(binding_index)}); | ||
| 1256 | + } else if ((binding_index >= 0) && | ||
| 1257 | + ((desc.outputs[j] == nullptr) || (static_cast<size_t>(binding_index) >= external_binding_num))) { | ||
| 1258 | + AICPUE_LOGE( | ||
| 1259 | + "Invalid fused output binding: node_index[%zu], output_index[%zu], binding_index[%d], " | ||
| 1260 | + "external_binding_num[%zu], output_null[%d].", | ||
| 1261 | + AICPUE_ERROR_CODE, node_index, j, binding_index, external_binding_num, | ||
| 1262 | + static_cast<int32_t>(desc.outputs[j] == nullptr)); | ||
| 1263 | + return -1; | ||
| 1264 | + } | ||
| 1265 | + } | ||
| 1266 | + return 0; | ||
| 1267 | +} | ||
| 1268 | + | ||
| 1269 | +int32_t InitializeFusedChainNode(const FusedCpuKernelChainNodeDesc &desc, const size_t node_index, | ||
| 1270 | + const size_t external_binding_num, FusedCpuKernelChainPlan &chain) { | ||
| 1271 | + if ((desc.op == nullptr) || ((desc.input_num != 0U) && (desc.inputs == nullptr)) || | ||
| 1272 | + ((desc.output_num != 0U) && (desc.outputs == nullptr))) { | ||
| 1273 | + AICPUE_LOGE( | ||
| 1274 | + "Invalid fused CPU chain node descriptor: node_index[%zu], op_null[%d], input_num[%zu], " | ||
| 1275 | + "inputs_null[%d], output_num[%zu], outputs_null[%d].", | ||
| 1276 | + AICPUE_ERROR_CODE, node_index, static_cast<int32_t>(desc.op == nullptr), desc.input_num, | ||
| 1277 | + static_cast<int32_t>(desc.inputs == nullptr), desc.output_num, static_cast<int32_t>(desc.outputs == nullptr)); | ||
| 1278 | + return -1; | ||
| 1279 | + } | ||
| 1280 | + chain.nodes.emplace_back(); | ||
| 1281 | + FusedCpuKernelChainNode &node = chain.nodes.back(); | ||
| 1282 | + const int32_t init_ret = | ||
| 1283 | + InitializeFusedCpuKernelPlan(*desc.op, desc.inputs, desc.input_num, desc.outputs, desc.output_num, node.plan); | ||
| 1284 | + if (init_ret != 0) { | ||
| 1285 | + AICPUE_LOGE("Initialize fused CPU kernel plan failed: node_index[%zu], input_num[%zu], output_num[%zu], ret[%d].", | ||
| 1286 | + AICPUE_ERROR_CODE, node_index, desc.input_num, desc.output_num, init_ret); | ||
| 1287 | + return -1; | ||
| 1288 | + } | ||
| 1289 | + if ((node.plan.input_tensors.size() != desc.input_num) || (node.plan.input_states.size() != desc.input_num) || | ||
| 1290 | + (node.plan.output_tensors.size() != desc.output_num) || (node.plan.output_states.size() != desc.output_num)) { | ||
| 1291 | + AICPUE_LOGE( | ||
| 1292 | + "Fused CPU kernel plan size mismatch: node_index[%zu], expected inputs[%zu], input_states[%zu], " | ||
| 1293 | + "outputs[%zu], output_states[%zu], actual inputs[%zu], input_states[%zu], outputs[%zu], " | ||
| 1294 | + "output_states[%zu].", | ||
| 1295 | + AICPUE_ERROR_CODE, node_index, desc.input_num, desc.input_num, desc.output_num, desc.output_num, | ||
| 1296 | + node.plan.input_tensors.size(), node.plan.input_states.size(), node.plan.output_tensors.size(), | ||
| 1297 | + node.plan.output_states.size()); | ||
| 1298 | + return -1; | ||
| 1299 | + } | ||
| 1300 | + return (AddFusedChainInputBindings(desc, node_index, external_binding_num, node, chain) == 0) && | ||
| 1301 | + (AddFusedChainOutputBindings(desc, node_index, external_binding_num, node, chain) == 0) | ||
| 1302 | + ? 0 | ||
| 1303 | + : -1; | ||
| 1304 | +} | ||
| 1305 | + | ||
| 1306 | +__attribute__((visibility("default"))) void *CreateCpuConstantFoldingFusedChainPlan(const void *node_descs, | ||
| 1307 | + const size_t node_num, | ||
| 1308 | + const size_t external_input_num, | ||
| 1309 | + const size_t external_output_num) { | ||
| 1310 | + if ((node_descs == nullptr) || (node_num == 0U)) { | ||
| 1311 | + AICPUE_LOGE( | ||
| 1312 | + "Invalid fused CPU chain plan arguments: node_descs_null[%d], node_num[%zu], external_inputs[%zu], " | ||
| 1313 | + "external_outputs[%zu].", | ||
| 1314 | + AICPUE_ERROR_CODE, static_cast<int32_t>(node_descs == nullptr), node_num, external_input_num, | ||
| 1315 | + external_output_num); | ||
| 1316 | + return nullptr; | ||
| 1317 | + } | ||
| 1318 | + const auto *descs = static_cast<const FusedCpuKernelChainNodeDesc *>(node_descs); | ||
| 1319 | + std::unique_ptr<FusedCpuKernelChainPlan> chain = std::make_unique<FusedCpuKernelChainPlan>(); | ||
| 1320 | + | ||
| 1321 | + // 防止计算外部 binding 数量时发生 size_t 整数溢出 | ||
| 1322 | + if (external_input_num > (std::numeric_limits<size_t>::max() - external_output_num)) { | ||
| 1323 | + AICPUE_LOGE("Fused CPU chain external binding count overflows size_t: external_inputs[%zu], external_outputs[%zu].", | ||
| 1324 | + AICPUE_ERROR_CODE, external_input_num, external_output_num); | ||
| 1325 | + return nullptr; | ||
| 1326 | + } | ||
| 1327 | + const size_t external_binding_num = external_input_num + external_output_num; | ||
| 1328 | + chain->nodes.reserve(node_num); | ||
| 1329 | + size_t binding_capacity = 0U; | ||
| 1330 | + if (CalculateFusedChainBindingCapacity(descs, node_num, binding_capacity) != 0) { | ||
| 1331 | + return nullptr; | ||
| 1332 | + } | ||
| 1333 | + chain->bindings.reserve(binding_capacity); | ||
| 1334 | + for (size_t i = 0U; i < node_num; ++i) { | ||
| 1335 | + if (InitializeFusedChainNode(descs[i], i, external_binding_num, *chain) != 0) { | ||
| 1336 | + return nullptr; | ||
| 1337 | + } | ||
| 1338 | + } | ||
| 1339 | + AICPUE_LOGD("Created fused cpu chain execution plan, nodes[%zu], dynamic bindings[%zu].", node_num, | ||
| 1340 | + chain->bindings.size()); | ||
| 1341 | + return chain.release(); | ||
| 1342 | +} | ||
| 1343 | + | ||
| 1344 | +__attribute__((visibility("default"))) int32_t RunCpuConstantFoldingFusedChainPlan(void *plan, | ||
| 1345 | + const uint32_t binding_flags) { | ||
| 1346 | + FusedCpuKernelChainPlan *chain = static_cast<FusedCpuKernelChainPlan *>(plan); | ||
| 1347 | + if (chain == nullptr) { | ||
| 1348 | + AICPUE_LOGE("Run fused CPU chain plan received null plan: binding_flags[%u].", AICPUE_ERROR_CODE, binding_flags); | ||
| 1349 | + return -1; | ||
| 1350 | + } | ||
| 1351 | + if (binding_flags != 0U) { | ||
| 1352 | + for (FusedCpuKernelBinding &binding : chain->bindings) { | ||
| 1353 | + if (RebindFusedTensorByFlags(*binding.source, binding.target, *binding.state, binding_flags) != 0) { | ||
| 1354 | + AICPUE_LOGE("Failed to rebind fused CPU chain binding: binding_index[%zu], flags[%u].", AICPUE_ERROR_CODE, | ||
| 1355 | + binding.binding_index, binding_flags); | ||
| 1356 | + return -1; | ||
| 1357 | + } | ||
| 1358 | + } | ||
| 1359 | + } | ||
| 1360 | + for (size_t node_index = 0U; node_index < chain->nodes.size(); ++node_index) { | ||
| 1361 | + if (RunFusedCpuKernelPlan(chain->nodes[node_index].plan) != 0) { | ||
| 1362 | + AICPUE_LOGE("Failed to run fused CPU chain node: node_index[%zu], node_count[%zu].", AICPUE_ERROR_CODE, | ||
| 1363 | + node_index, chain->nodes.size()); | ||
| 1364 | + return -1; | ||
| 1365 | + } | ||
| 1366 | + } | ||
| 1367 | + return 0; | ||
| 1368 | +} | ||
| 1369 | + | ||
| 1370 | +__attribute__((visibility("default"))) int32_t | ||
| 1371 | +RunCpuConstantFoldingFusedChainPlanBindings(void *plan, const void *binding_data, const uint32_t binding_flags) { | ||
| 1372 | + FusedCpuKernelChainPlan *chain = static_cast<FusedCpuKernelChainPlan *>(plan); | ||
| 1373 | + if (chain == nullptr) { | ||
| 1374 | + AICPUE_LOGE("Run fused CPU chain bindings received null plan: binding_flags[%u].", AICPUE_ERROR_CODE, | ||
| 1375 | + binding_flags); | ||
| 1376 | + return -1; | ||
| 1377 | + } | ||
| 1378 | + if (binding_flags != 0U) { | ||
| 1379 | + if (binding_data == nullptr) { | ||
| 1380 | + AICPUE_LOGE("Run fused CPU chain bindings received null binding data: binding_flags[%u], binding_count[%zu].", | ||
| 1381 | + AICPUE_ERROR_CODE, binding_flags, chain->bindings.size()); | ||
| 1382 | + return -1; | ||
| 1383 | + } | ||
| 1384 | + const auto *bindings = static_cast<const FusedHostCpuTensorBinding *>(binding_data); | ||
| 1385 | + for (FusedCpuKernelBinding &binding : chain->bindings) { | ||
| 1386 | + const FusedHostCpuTensorBinding *runtime_binding = &bindings[binding.binding_index]; | ||
| 1387 | + if ((runtime_binding->flags != 0U) && | ||
| 1388 | + (RebindFusedTensorByBinding(*runtime_binding, binding.target, *binding.state) != 0)) { | ||
| 1389 | + AICPUE_LOGE( | ||
| 1390 | + "Failed to rebind fused CPU runtime binding: binding_index[%zu], runtime_flags[%u], " | ||
| 1391 | + "global_flags[%u].", | ||
| 1392 | + AICPUE_ERROR_CODE, binding.binding_index, runtime_binding->flags, binding_flags); | ||
| 1393 | + return -1; | ||
| 1394 | + } | ||
| 1395 | + } | ||
| 1396 | + } | ||
| 1397 | + for (size_t node_index = 0U; node_index < chain->nodes.size(); ++node_index) { | ||
| 1398 | + if (RunFusedCpuKernelPlan(chain->nodes[node_index].plan) != 0) { | ||
| 1399 | + AICPUE_LOGE("Failed to run fused CPU chain node with runtime bindings: node_index[%zu], node_count[%zu].", | ||
| 1400 | + AICPUE_ERROR_CODE, node_index, chain->nodes.size()); | ||
| 1401 | + return -1; | ||
| 1402 | + } | ||
| 1403 | + } | ||
| 1404 | + return 0; | ||
| 1405 | +} | ||
| 1406 | + | ||
| 1407 | +__attribute__((visibility("default"))) void DestroyCpuConstantFoldingFusedChainPlan(void *plan) { | ||
| 1408 | + delete static_cast<FusedCpuKernelChainPlan *>(plan); | ||
| 1409 | +} | ||
| 700 | } | 1410 | } |
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | + | ||
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | 23 | ||
| @@ -27,8 +28,23 @@ | |||
| 27 | extern "C" { | 28 | extern "C" { |
| 28 | __attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::HostCpuOp *(*create_fn)()); | 29 | __attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::HostCpuOp *(*create_fn)()); |
| 29 | 30 | ||
| 31 | +__attribute__((visibility("default"))) int32_t IsCpuConstantFoldingFusedOpSupported(const char *op_type); | ||
| 32 | + | ||
| 30 | __attribute__((visibility("default"))) int32_t | 33 | __attribute__((visibility("default"))) int32_t |
| 31 | CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs, | 34 | CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs, |
| 32 | std::map<std::string, ge::Tensor> outputs); | 35 | std::map<std::string, ge::Tensor> outputs); |
| 36 | + | ||
| 37 | +__attribute__((visibility("default"))) void *CreateCpuConstantFoldingFusedChainPlan(const void *node_descs, | ||
| 38 | + size_t node_num, | ||
| 39 | + size_t external_input_num, | ||
| 40 | + size_t external_output_num); | ||
| 41 | + | ||
| 42 | +__attribute__((visibility("default"))) int32_t RunCpuConstantFoldingFusedChainPlan(void *plan, uint32_t binding_flags); | ||
| 43 | + | ||
| 44 | +__attribute__((visibility("default"))) int32_t RunCpuConstantFoldingFusedChainPlanBindings(void *plan, | ||
| 45 | + const void *bindings, | ||
| 46 | + uint32_t binding_flags); | ||
| 47 | + | ||
| 48 | +__attribute__((visibility("default"))) void DestroyCpuConstantFoldingFusedChainPlan(void *plan); | ||
| 33 | } | 49 | } |
| 34 | 50 | ||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | + | ||
| 31 | 32 | ||
| 32 | using namespace std; | 33 | using namespace std; |
| 33 | using namespace ge; | 34 | using namespace ge; |
| @@ -279,12 +280,24 @@ static ge::Status FillOutputTensorOfAicpuNodeDef(const ge::OpDescPtr &op_desc_pt | |||
| 279 | aicpu_shape->set_data_format(static_cast<ge::Format>(output_desc.GetFormat())); | 280 | aicpu_shape->set_data_format(static_cast<ge::Format>(output_desc.GetFormat())); |
| 280 | aicpu_shape->set_unknown_rank(is_unknow_shape); | 281 | aicpu_shape->set_unknown_rank(is_unknow_shape); |
| 281 | output_tensor->set_tensor_type(static_cast<ge::DataType>(output_desc.GetDataType())); | 282 | output_tensor->set_tensor_type(static_cast<ge::DataType>(output_desc.GetDataType())); |
| 283 | + if (op_desc_ptr->GetType() == ge::kFusedHostCpuOpType) { | ||
| 284 | + output_tensor->set_name(op_desc_ptr->GetOutputNameByIndex(static_cast<uint32_t>(i))); | ||
| 285 | + } | ||
| 282 | } | 286 | } |
| 283 | return ge::SUCCESS; | 287 | return ge::SUCCESS; |
| 284 | } | 288 | } |
| 285 | 289 | ||
| 286 | ge::Status BuildAicpuNodeDef(const ge::OpDescPtr &op_desc_ptr, aicpuops::NodeDef &node_def) { | 290 | ge::Status BuildAicpuNodeDef(const ge::OpDescPtr &op_desc_ptr, aicpuops::NodeDef &node_def) { |
| 287 | std::string op_type = op_desc_ptr->GetType(); | 291 | std::string op_type = op_desc_ptr->GetType(); |
| 292 | + // 将通用节点类型替换成动态 Kernel 注册名 | ||
| 293 | + if (op_type == ge::kFusedHostCpuOpType) { | ||
| 294 | + if (!ge::AttrUtils::GetStr(op_desc_ptr, ge::kFusedHostCpuRegisterName, op_type) || op_type.empty()) { | ||
| 295 | + AICPUE_LOGE("Get fused HostCPU register name failed for op [%s].", op_desc_ptr->GetName().c_str()); | ||
| 296 | + return ge::PARAM_INVALID; | ||
| 297 | + } | ||
| 298 | + AICPUE_LOGD("Resolve fused HostCPU node[%s] to dynamic kernel[%s].", op_desc_ptr->GetName().c_str(), | ||
| 299 | + op_type.c_str()); | ||
| 300 | + } | ||
| 288 | node_def.set_op(op_type); | 301 | node_def.set_op(op_type); |
| 289 | 302 | ||
| 290 | bool is_unknow_shape = false; | 303 | bool is_unknow_shape = false; |
Mcompiler/engines/cpu_engine/cpu_engine/hostcpu_engine/kernel_builder/hostcpu_ops_kernel_builder.cpp+17-2
| @@ -13,9 +13,11 @@ | |||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | + | ||
| 16 | 17 | ||
| 17 | 18 | ||
| 18 | 19 | ||
| 20 | + | ||
| 19 | 21 | ||
| 20 | 22 | ||
| 21 | 23 | ||
| @@ -61,7 +63,6 @@ ge::Status HostCpuOpsKernelBuilder::CalcOpRunningParam(ge::Node &node) { | |||
| 61 | ge::OpDescUtilsEx::SetType(op_desc_ptr, *op_original_type); | 63 | ge::OpDescUtilsEx::SetType(op_desc_ptr, *op_original_type); |
| 62 | op_type = *op_original_type; | 64 | op_type = *op_original_type; |
| 63 | } | 65 | } |
| 64 | - | ||
| 65 | FACTORY_ENGINE::FactoryType host_engine_ptr = FACTORY_ENGINE::Produce(engine_name_); | 66 | FACTORY_ENGINE::FactoryType host_engine_ptr = FACTORY_ENGINE::Produce(engine_name_); |
| 66 | AICPU_CHECK_NOTNULL_ERRCODE(host_engine_ptr, ErrorCode::INPUT_PARAM_NULL) | 67 | AICPU_CHECK_NOTNULL_ERRCODE(host_engine_ptr, ErrorCode::INPUT_PARAM_NULL) |
| 67 | AicpuOpsKernelInfoStorePtr host_ops_kernel_info_store_ptr = host_engine_ptr->GetAicpuOpsKernelInfoStore(); | 68 | AicpuOpsKernelInfoStorePtr host_ops_kernel_info_store_ptr = host_engine_ptr->GetAicpuOpsKernelInfoStore(); |
| @@ -77,7 +78,17 @@ ge::Status HostCpuOpsKernelBuilder::CalcOpRunningParam(ge::Node &node) { | |||
| 77 | AICPUE_LOGI("Node[%s] set attr optional_input_placeholder is [%s]", node.GetName().c_str(), | 78 | AICPUE_LOGI("Node[%s] set attr optional_input_placeholder is [%s]", node.GetName().c_str(), |
| 78 | optional_input ? "true" : "false"); | 79 | optional_input ? "true" : "false"); |
| 79 | } | 80 | } |
| 80 | - | 81 | + if ((op_type == ge::kFusedHostCpuOpType) && !ge::AttrUtils::HasAttr(op_desc_ptr, kCustomizedOpDef)) { |
| 82 | + // 首次构建时将动态注册名和完整 IO 描述写入 NodeDef,后续沿用通用 HostCPU TaskDef 生成流程。 | ||
| 83 | + AICPUE_LOGD("Build customized NodeDef for fused HostCPU node[%s], inputs[%zu], outputs[%zu].", | ||
| 84 | + node.GetName().c_str(), op_desc_ptr->GetAllInputsSize(), op_desc_ptr->GetOutputsSize()); | ||
| 85 | + aicpuops::NodeDef node_def; | ||
| 86 | + AICPU_CHECK_RES_WITH_LOG(BuildAicpuNodeDef(op_desc_ptr, node_def), "Build NodeDef for fused HostCPU op[%s] failed.", | ||
| 87 | + node.GetName().c_str()); | ||
| 88 | + AICPU_CHECK_RES_WITH_LOG(InsertAicpuNodeDefAttrToOp(op_desc_ptr, node_def, kCustomizedOpDef), | ||
| 89 | + "Serialize NodeDef for fused HostCPU op[%s] failed.", node.GetName().c_str()); | ||
| 90 | + AICPUE_LOGD("Customized NodeDef is ready for fused HostCPU node[%s].", node.GetName().c_str()); | ||
| 91 | + } | ||
| 81 | const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"]; | 92 | const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"]; |
| 82 | AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER); | 93 | AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER); |
| 83 | return kernel_builder->CalcOpRunningParam(node); | 94 | return kernel_builder->CalcOpRunningParam(node); |
| @@ -101,6 +112,10 @@ ge::Status HostCpuOpsKernelBuilder::GenerateTask(const ge::Node &ge_node, ge::Ru | |||
| 101 | 112 | ||
| 102 | const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"]; | 113 | const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"]; |
| 103 | AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER); | 114 | AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER); |
| 115 | + if (op_type == ge::kFusedHostCpuOpType) { | ||
| 116 | + // TaskDef 仍走通用 HOSTCPUBuilder;其中的 NodeDef 已将公共类型替换为 JIT kernel 注册名。 | ||
| 117 | + AICPUE_LOGD("Generate generic HostCPU task for fused node[%s].", ge_node.GetName().c_str()); | ||
| 118 | + } | ||
| 104 | return kernel_builder->GenerateTask(ge_node, context, tasks); | 119 | return kernel_builder->GenerateTask(ge_node, context, tasks); |
| 105 | } | 120 | } |
| 106 | 121 | ||
| @@ -34,7 +34,6 @@ | |||
| 34 | 34 | ||
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | - | ||
| 38 | 37 | ||
| 39 | namespace ge { | 38 | namespace ge { |
| 40 | namespace { | 39 | namespace { |
| @@ -51,7 +50,6 @@ const char_t *const kAnchorIndex = "anchorIndex"; | |||
| 51 | const char_t *const kTaskL2FusionInfo = "_task_L2FusionInfo"; | 50 | const char_t *const kTaskL2FusionInfo = "_task_L2FusionInfo"; |
| 52 | const char_t *const kDataAnchorIndexForLxfusion = "_data_anchor_index_for_lxfusion"; | 51 | const char_t *const kDataAnchorIndexForLxfusion = "_data_anchor_index_for_lxfusion"; |
| 53 | const char_t *const kEnableCvParallel = "_enable_cv_parallel"; | 52 | const char_t *const kEnableCvParallel = "_enable_cv_parallel"; |
| 54 | -const char_t *const kSoBufferAttr = "bin_file_buffer"; | ||
| 55 | const char_t *const kVectorEngineName = "VectorEngine"; | 53 | const char_t *const kVectorEngineName = "VectorEngine"; |
| 56 | const char_t *const kHostCpuEngineName = "DNN_VM_HOST_CPU"; | 54 | const char_t *const kHostCpuEngineName = "DNN_VM_HOST_CPU"; |
| 57 | const std::string kStableRdfsSort = "3"; | 55 | const std::string kStableRdfsSort = "3"; |
| @@ -482,20 +480,6 @@ Status EnginePartitioner::InheritOriginalAttr(const ComputeGraphPtr &original_co | |||
| 482 | output_merged_compute_graph->SetExtAttr(ge::ATTR_NAME_DEVICE_INDEX_TO_LOGIC_DEVICE_ID, *device_mapping)); | 480 | output_merged_compute_graph->SetExtAttr(ge::ATTR_NAME_DEVICE_INDEX_TO_LOGIC_DEVICE_ID, *device_mapping)); |
| 483 | } | 481 | } |
| 484 | 482 | ||
| 485 | - // HostCPU fusion stores generated custom-op SOs in this ext attr. The merge step | ||
| 486 | - // creates a new graph, so preserve the buffer together with the graph attrs. | ||
| 487 | - const auto so_buffer = original_compute_graph->GetExtAttr<std::map<std::string, ge::OpSoBinPtr>>(kSoBufferAttr); | ||
| 488 | - if (so_buffer != nullptr) { | ||
| 489 | - std::map<std::string, ge::OpSoBinPtr> merged_so_buffer; | ||
| 490 | - const auto existing_so_buffer = | ||
| 491 | - output_merged_compute_graph->GetExtAttr<std::map<std::string, ge::OpSoBinPtr>>(kSoBufferAttr); | ||
| 492 | - if (existing_so_buffer != nullptr) { | ||
| 493 | - merged_so_buffer = *existing_so_buffer; | ||
| 494 | - } | ||
| 495 | - merged_so_buffer.insert(so_buffer->begin(), so_buffer->end()); | ||
| 496 | - GE_ASSERT_TRUE(output_merged_compute_graph->SetExtAttr(kSoBufferAttr, merged_so_buffer)); | ||
| 497 | - } | ||
| 498 | - | ||
| 499 | // AttrStore里面属性组没有被拷贝,并且没有提供CopyAllAttrStore方法,暂时先手动拷贝必须的 | 483 | // AttrStore里面属性组没有被拷贝,并且没有提供CopyAllAttrStore方法,暂时先手动拷贝必须的 |
| 500 | auto origin_shape_env_attr = original_compute_graph->GetAttrsGroup<ShapeEnvAttr>(); | 484 | auto origin_shape_env_attr = original_compute_graph->GetAttrsGroup<ShapeEnvAttr>(); |
| 501 | if (origin_shape_env_attr != nullptr) { | 485 | if (origin_shape_env_attr != nullptr) { |
| @@ -34,7 +34,7 @@ struct HostCpuFusionRegion { | |||
| 34 | std::vector<HostCpuFusionOutput> external_outputs; | 34 | std::vector<HostCpuFusionOutput> external_outputs; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | -// source 用于维测和测试,so_data 作为标准 custom-op SO 写入模型。 | 37 | +// source 用于维测和测试,so_data 写入图属性并在运行时加载。 |
| 38 | struct HostCpuFusionCodegenResult { | 38 | struct HostCpuFusionCodegenResult { |
| 39 | std::string register_name; | 39 | std::string register_name; |
| 40 | std::string source; | 40 | std::string source; |
| @@ -50,8 +50,8 @@ class HostCpuFusionCompiler { | |||
| 50 | virtual Status Compile(const std::string &source, std::vector<uint8_t> &so_data) const; | 50 | virtual Status Compile(const std::string &source, std::vector<uint8_t> &so_data) const; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | -// 生成注册到 CustomOpRegistry(kHostCPU) 的普通 HostCpuExecuteOp。执行时按 op_type 从 | 53 | +// 生成注册到 aicpu::CpuKernelRegister 的融合 CpuKernel;内部编排为每个原始算子缓存 CpuKernel 执行计划, |
| 54 | -// libconstant_folding_ops.so 查询 Gert HostKernel,并使用临时 KernelContext 按拓扑序执行。 | 54 | +// 稳态仅更新 Tensor 数据和变化的描述信息并按拓扑序执行。 |
| 55 | class HostCpuFusionCodegen { | 55 | class HostCpuFusionCodegen { |
| 56 | public: | 56 | public: |
| 57 | Status Generate(const HostCpuFusionRegion ®ion, HostCpuFusionCodegenResult &result) const; | 57 | Status Generate(const HostCpuFusionRegion ®ion, HostCpuFusionCodegenResult &result) const; |
| @@ -14,23 +14,14 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | 17 | ||
| 21 | 18 | ||
| 22 | 19 | ||
| 23 | 20 | ||
| 24 | 21 | ||
| 25 | 22 | ||
| 26 | - | ||
| 27 | - | ||
| 28 | - | ||
| 29 | - | ||
| 30 | 23 | ||
| 31 | - | ||
| 32 | 24 | ||
| 33 | - | ||
| 34 | 25 | ||
| 35 | 26 | ||
| 36 | 27 | ||
| @@ -40,9 +31,10 @@ namespace { | |||
| 40 | constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U; | 31 | constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U; |
| 41 | constexpr char kHostCpuEngineName[] = "DNN_VM_HOST_CPU"; | 32 | constexpr char kHostCpuEngineName[] = "DNN_VM_HOST_CPU"; |
| 42 | constexpr char kHostCpuKernelLibName[] = "DNN_VM_HOST_CPU_OP_STORE"; | 33 | constexpr char kHostCpuKernelLibName[] = "DNN_VM_HOST_CPU_OP_STORE"; |
| 34 | +constexpr char kHostCpuTaskKernelLibName[] = "HOSTCPUKernel"; | ||
| 35 | +constexpr char kOpKernelLibAttr[] = "opKernelLib"; | ||
| 43 | constexpr char kSmallShapeHostCpu[] = "SmallShapeHostcpu"; | 36 | constexpr char kSmallShapeHostCpu[] = "SmallShapeHostcpu"; |
| 44 | constexpr char kResourceListAttr[] = "_resource_list"; | 37 | constexpr char kResourceListAttr[] = "_resource_list"; |
| 45 | -constexpr char kSoBufferAttr[] = "bin_file_buffer"; | ||
| 46 | 38 | ||
| 47 | bool IsValidFusedHostCpuSoElf(const std::vector<uint8_t> &data) { | 39 | bool IsValidFusedHostCpuSoElf(const std::vector<uint8_t> &data) { |
| 48 | return (data.size() >= 20U) && (data.size() <= kMaxGeneratedSoSize) && (data[0] == 0x7FU) && (data[1] == 'E') && | 40 | return (data.size() >= 20U) && (data.size() <= kMaxGeneratedSoSize) && (data[0] == 0x7FU) && (data[1] == 'E') && |
| @@ -140,8 +132,7 @@ bool IsCandidate(const NodePtr &node, const HostCpuFusionOpSupportChecker &op_su | |||
| 140 | GELOGD("Skip HostCPU fusion node[%s]: OpDesc is null.", node->GetNamePtr()); | 132 | GELOGD("Skip HostCPU fusion node[%s]: OpDesc is null.", node->GetNamePtr()); |
| 141 | return false; | 133 | return false; |
| 142 | } | 134 | } |
| 143 | - bool generated = false; | 135 | + if (node->GetType() == kFusedHostCpuOpType) { |
| 144 | - if (AttrUtils::GetBool(node->GetOpDesc(), kFusedHostCpuGenerated, generated) && generated) { | ||
| 145 | GELOGD("Skip HostCPU fusion node[%s]: node is already fused.", node->GetNamePtr()); | 136 | GELOGD("Skip HostCPU fusion node[%s]: node is already fused.", node->GetNamePtr()); |
| 146 | return false; | 137 | return false; |
| 147 | } | 138 | } |
| @@ -327,15 +318,10 @@ std::vector<NodePtr> GetComponentSinks(const std::vector<NodePtr> &component, | |||
| 327 | return sinks; | 318 | return sinks; |
| 328 | } | 319 | } |
| 329 | 320 | ||
| 330 | -std::unordered_set<const Node *> CollectComponentAncestors(const std::unordered_set<const Node *> &component_set, | 321 | +HostCpuFusionRegion BuildRegionForSink(const std::vector<NodePtr> &topological_nodes, |
| 331 | - const NodePtr &sink) { | 322 | + const std::unordered_set<const Node *> &component_set, const NodePtr &sink) { |
| 332 | std::unordered_set<const Node *> ancestors; | 323 | std::unordered_set<const Node *> ancestors; |
| 333 | - std::deque<NodePtr> pending; | 324 | + std::deque<NodePtr> pending{sink}; |
| 334 | - for (const auto &in_node : sink->GetInDataNodes()) { | ||
| 335 | - if (component_set.count(in_node.get()) > 0U) { | ||
| 336 | - pending.emplace_back(in_node); | ||
| 337 | - } | ||
| 338 | - } | ||
| 339 | while (!pending.empty()) { | 325 | while (!pending.empty()) { |
| 340 | const auto current = pending.front(); | 326 | const auto current = pending.front(); |
| 341 | pending.pop_front(); | 327 | pending.pop_front(); |
| @@ -348,46 +334,10 @@ std::unordered_set<const Node *> CollectComponentAncestors(const std::unordered_ | |||
| 348 | } | 334 | } |
| 349 | } | 335 | } |
| 350 | } | 336 | } |
| 351 | - return ancestors; | ||
| 352 | -} | ||
| 353 | - | ||
| 354 | -bool HasSameAncestors(const std::unordered_set<const Node *> &lhs, const std::unordered_set<const Node *> &rhs) { | ||
| 355 | - return (lhs.size() == rhs.size()) && | ||
| 356 | - std::all_of(lhs.cbegin(), lhs.cend(), [&rhs](const Node *node) { return rhs.count(node) > 0U; }); | ||
| 357 | -} | ||
| 358 | - | ||
| 359 | -struct SinkAncestorGroup { | ||
| 360 | - std::unordered_set<const Node *> ancestors; | ||
| 361 | - std::vector<NodePtr> sinks; | ||
| 362 | -}; | ||
| 363 | - | ||
| 364 | -std::vector<SinkAncestorGroup> GroupSinksByAncestors(const std::unordered_set<const Node *> &component_set, | ||
| 365 | - const std::vector<NodePtr> &sinks) { | ||
| 366 | - std::vector<SinkAncestorGroup> groups; | ||
| 367 | - for (const auto &sink : sinks) { | ||
| 368 | - auto ancestors = CollectComponentAncestors(component_set, sink); | ||
| 369 | - const auto group = std::find_if(groups.begin(), groups.end(), [&ancestors](const SinkAncestorGroup &candidate) { | ||
| 370 | - return HasSameAncestors(candidate.ancestors, ancestors); | ||
| 371 | - }); | ||
| 372 | - if (group != groups.end()) { | ||
| 373 | - group->sinks.emplace_back(sink); | ||
| 374 | - continue; | ||
| 375 | - } | ||
| 376 | - groups.push_back({std::move(ancestors), {sink}}); | ||
| 377 | - } | ||
| 378 | - return groups; | ||
| 379 | -} | ||
| 380 | - | ||
| 381 | -HostCpuFusionRegion BuildRegionForSinkGroup(const std::vector<NodePtr> &topological_nodes, | ||
| 382 | - const SinkAncestorGroup &group) { | ||
| 383 | - std::unordered_set<const Node *> region_nodes = group.ancestors; | ||
| 384 | - for (const auto &sink : group.sinks) { | ||
| 385 | - region_nodes.emplace(sink.get()); | ||
| 386 | - } | ||
| 387 | 337 | ||
| 388 | HostCpuFusionRegion region; | 338 | HostCpuFusionRegion region; |
| 389 | for (const auto &node : topological_nodes) { | 339 | for (const auto &node : topological_nodes) { |
| 390 | - if (region_nodes.count(node.get()) > 0U) { | 340 | + if (ancestors.count(node.get()) > 0U) { |
| 391 | region.nodes.emplace_back(node); | 341 | region.nodes.emplace_back(node); |
| 392 | } | 342 | } |
| 393 | } | 343 | } |
| @@ -469,17 +419,14 @@ Status BuildComponentRegions(const ComputeGraphPtr &graph, const std::vector<Nod | |||
| 469 | sinks.size()); | 419 | sinks.size()); |
| 470 | return FAILED; | 420 | return FAILED; |
| 471 | } | 421 | } |
| 472 | - GELOGD("HostCPU fusion component[%zu] contains %zu nodes and %zu sinks, ancestor_grouping=%d, nodes=[%s].", | 422 | + GELOGD("HostCPU fusion component[%zu] contains %zu nodes and %zu sinks, clone_and_split=%d, nodes=[%s].", |
| 473 | component_index, component.size(), sinks.size(), static_cast<int32_t>(requires_split), | 423 | component_index, component.size(), sinks.size(), static_cast<int32_t>(requires_split), |
| 474 | GetNodeNames(component).c_str()); | 424 | GetNodeNames(component).c_str()); |
| 475 | - const auto sink_groups = GroupSinksByAncestors(component_set, sinks); | 425 | + for (const auto &sink : sinks) { |
| 476 | - GELOGD("HostCPU fusion component[%zu] groups %zu sinks into %zu ancestor group(s).", component_index, sinks.size(), | 426 | + auto region = BuildRegionForSink(topological_nodes, component_set, sink); |
| 477 | - sink_groups.size()); | ||
| 478 | - for (const auto &group : sink_groups) { | ||
| 479 | - auto region = BuildRegionForSinkGroup(topological_nodes, group); | ||
| 480 | if (region.nodes.size() < 2U) { | 427 | if (region.nodes.size() < 2U) { |
| 481 | - GELOGD("Skip HostCPU fusion component[%zu] sink group[%s]: ancestor region has only %zu node(s).", | 428 | + GELOGD("Skip HostCPU fusion component[%zu] sink[%s]: ancestor region has only %zu node(s).", component_index, |
| 482 | - component_index, GetNodeNames(group.sinks).c_str(), region.nodes.size()); | 429 | + sink->GetNamePtr(), region.nodes.size()); |
| 483 | continue; | 430 | continue; |
| 484 | } | 431 | } |
| 485 | regions.emplace_back(std::move(region)); | 432 | regions.emplace_back(std::move(region)); |
| @@ -533,15 +480,16 @@ bool AddFusedOutputDescs(const HostCpuFusionRegion ®ion, const OpDescPtr &op_ | |||
| 533 | } | 480 | } |
| 534 | 481 | ||
| 535 | bool SetFusedOpAttributes(const PreparedFusionRegion &prepared, const OpDescPtr &op_desc) { | 482 | bool SetFusedOpAttributes(const PreparedFusionRegion &prepared, const OpDescPtr &op_desc) { |
| 536 | - op_desc->SetOpEngineName(kEngineNameCustom); | 483 | + const auto ®ion = prepared.region; |
| 537 | - op_desc->SetOpKernelLibName(kCustomOpKernelLibName); | 484 | + op_desc->SetOpEngineName(kHostCpuEngineName); |
| 538 | - return AttrUtils::SetStr(op_desc, ATTR_NAME_ENGINE_NAME_FOR_LX, kEngineNameCustom) && | 485 | + op_desc->SetOpKernelLibName(kHostCpuKernelLibName); |
| 539 | - AttrUtils::SetStr(op_desc, ATTR_NAME_KKERNEL_LIB_NAME_FOR_LX, kCustomOpKernelLibName) && | 486 | + return AttrUtils::SetStr(op_desc, ATTR_NAME_ENGINE_NAME_FOR_LX, kHostCpuEngineName) && |
| 540 | - AttrUtils::SetStr(op_desc, kAttrLowingFunc, kHostCpuCustomOpLowerFunc) && | 487 | + AttrUtils::SetStr(op_desc, ATTR_NAME_KKERNEL_LIB_NAME_FOR_LX, kHostCpuKernelLibName) && |
| 488 | + AttrUtils::SetStr(op_desc, kOpKernelLibAttr, kHostCpuTaskKernelLibName) && | ||
| 541 | AttrUtils::SetInt(op_desc, ATTR_NAME_UNKNOWN_SHAPE_TYPE, DEPEND_IN_SHAPE) && | 489 | AttrUtils::SetInt(op_desc, ATTR_NAME_UNKNOWN_SHAPE_TYPE, DEPEND_IN_SHAPE) && |
| 542 | AttrUtils::SetBool(op_desc, kSmallShapeHostCpu, true) && | 490 | AttrUtils::SetBool(op_desc, kSmallShapeHostCpu, true) && |
| 543 | - AttrUtils::SetBool(op_desc, kFusedHostCpuGenerated, true) && | 491 | + AttrUtils::SetStr(op_desc, kFusedHostCpuRegisterName, prepared.codegen.register_name) && |
| 544 | - AttrUtils::SetStr(op_desc, kFusedHostCpuRegisterName, prepared.codegen.register_name); | 492 | + AttrUtils::SetStr(op_desc, kFusedHostCpuSoKey, std::string(kFusedHostCpuSoDataPrefix) + region.chain_id); |
| 545 | } | 493 | } |
| 546 | 494 | ||
| 547 | bool SetFusedOpMetadata(const HostCpuFusionRegion ®ion, const OpDescPtr &op_desc) { | 495 | bool SetFusedOpMetadata(const HostCpuFusionRegion ®ion, const OpDescPtr &op_desc) { |
| @@ -564,7 +512,8 @@ bool SetFusedOpMetadata(const HostCpuFusionRegion ®ion, const OpDescPtr &op_d | |||
| 564 | 512 | ||
| 565 | OpDescPtr CreateFusedOpDesc(const PreparedFusionRegion &prepared) { | 513 | OpDescPtr CreateFusedOpDesc(const PreparedFusionRegion &prepared) { |
| 566 | const auto ®ion = prepared.region; | 514 | const auto ®ion = prepared.region; |
| 567 | - auto op_desc = std::make_shared<OpDesc>(prepared.codegen.register_name, prepared.codegen.register_name); | 515 | + auto op_desc = |
| 516 | + std::make_shared<OpDesc>(std::string(kFusedHostCpuOpType) + "_" + region.chain_id, kFusedHostCpuOpType); | ||
| 568 | if (!AddFusedInputDescs(region, op_desc) || !AddFusedOutputDescs(region, op_desc)) { | 517 | if (!AddFusedInputDescs(region, op_desc) || !AddFusedOutputDescs(region, op_desc)) { |
| 569 | return nullptr; | 518 | return nullptr; |
| 570 | } | 519 | } |
| @@ -599,8 +548,10 @@ struct ReplacedFusionOutput { | |||
| 599 | OutDataAnchorPtr new_source; | 548 | OutDataAnchorPtr new_source; |
| 600 | }; | 549 | }; |
| 601 | 550 | ||
| 602 | -Status RollbackFusionCommit(const ComputeGraphPtr &graph, const std::vector<NodePtr> &fused_nodes, | 551 | +Status RollbackFusionCommit(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph, |
| 603 | - const std::vector<ReplacedFusionOutput> &replaced_outputs) { | 552 | + const std::vector<NodePtr> &fused_nodes, |
| 553 | + const std::vector<ReplacedFusionOutput> &replaced_outputs, | ||
| 554 | + const std::vector<std::string> &root_graph_so_keys) { | ||
| 604 | GELOGW("Rollback HostCPU fusion graph commit: graph[%s], new_nodes=%zu, replaced_edges=%zu.", | 555 | GELOGW("Rollback HostCPU fusion graph commit: graph[%s], new_nodes=%zu, replaced_edges=%zu.", |
| 605 | graph->GetName().c_str(), fused_nodes.size(), replaced_outputs.size()); | 556 | graph->GetName().c_str(), fused_nodes.size(), replaced_outputs.size()); |
| 606 | for (auto iter = replaced_outputs.rbegin(); iter != replaced_outputs.rend(); ++iter) { | 557 | for (auto iter = replaced_outputs.rbegin(); iter != replaced_outputs.rend(); ++iter) { |
| @@ -609,10 +560,28 @@ Status RollbackFusionCommit(const ComputeGraphPtr &graph, const std::vector<Node | |||
| 609 | graph->GetName().c_str(), static_cast<int32_t>(iter->consumer == nullptr)); | 560 | graph->GetName().c_str(), static_cast<int32_t>(iter->consumer == nullptr)); |
| 610 | } | 561 | } |
| 611 | } | 562 | } |
| 612 | - return RollbackNewNodes(graph, fused_nodes); | 563 | + const Status rollback_status = RollbackNewNodes(graph, fused_nodes); |
| 564 | + for (const auto &so_key : root_graph_so_keys) { | ||
| 565 | + if (root_graph->DelAttr(so_key) != GRAPH_SUCCESS) { | ||
| 566 | + GELOGE(FAILED, "Failed to remove rolled-back fused HostCPU SO data: graph[%s], so_key[%s].", | ||
| 567 | + root_graph->GetName().c_str(), so_key.c_str()); | ||
| 568 | + } | ||
| 569 | + } | ||
| 570 | + return rollback_status; | ||
| 613 | } | 571 | } |
| 614 | 572 | ||
| 615 | -NodePtr CreateFusedNode(const ComputeGraphPtr &graph, const PreparedFusionRegion &prepared) { | 573 | +NodePtr CreateAndRegisterFusedNode(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph, |
| 574 | + const PreparedFusionRegion &prepared, std::vector<std::string> &root_graph_so_keys, | ||
| 575 | + std::string &so_key) { | ||
| 576 | + so_key = std::string(kFusedHostCpuSoDataPrefix) + prepared.region.chain_id; | ||
| 577 | + if (AttrUtils::HasAttr(root_graph, so_key) || | ||
| 578 | + !AttrUtils::SetBytes(root_graph, so_key, | ||
| 579 | + Buffer::CopyFrom(prepared.codegen.so_data.data(), prepared.codegen.so_data.size()))) { | ||
| 580 | + GELOGE(FAILED, "Failed to set fused HostCPU graph SO data: graph[%s], so_key[%s], so_size=%zu.", | ||
| 581 | + graph->GetName().c_str(), so_key.c_str(), prepared.codegen.so_data.size()); | ||
| 582 | + return nullptr; | ||
| 583 | + } | ||
| 584 | + root_graph_so_keys.emplace_back(so_key); | ||
| 616 | const auto op_desc = CreateFusedOpDesc(prepared); | 585 | const auto op_desc = CreateFusedOpDesc(prepared); |
| 617 | if (op_desc == nullptr) { | 586 | if (op_desc == nullptr) { |
| 618 | GELOGE(FAILED, "Failed to create fused HostCPU OpDesc: graph[%s], chain[%s].", graph->GetName().c_str(), | 587 | GELOGE(FAILED, "Failed to create fused HostCPU OpDesc: graph[%s], chain[%s].", graph->GetName().c_str(), |
| @@ -630,9 +599,10 @@ NodePtr CreateFusedNode(const ComputeGraphPtr &graph, const PreparedFusionRegion | |||
| 630 | op_desc->GetName().c_str()); | 599 | op_desc->GetName().c_str()); |
| 631 | return nullptr; | 600 | return nullptr; |
| 632 | } | 601 | } |
| 633 | - GELOGD("HostCPU fusion adds custom-op node[%s]: chain[%s], so_size=%zu, inputs=%zu, outputs=%zu.", | 602 | + GELOGD("HostCPU fusion adds node[%s]: chain[%s], so_key[%s], so_graph[%s], so_size=%zu, inputs=%zu, outputs=%zu.", |
| 634 | - fused_node->GetNamePtr(), prepared.region.chain_id.c_str(), prepared.codegen.so_data.size(), | 603 | + fused_node->GetNamePtr(), prepared.region.chain_id.c_str(), so_key.c_str(), root_graph->GetName().c_str(), |
| 635 | - prepared.region.external_inputs.size(), prepared.region.external_outputs.size()); | 604 | + prepared.codegen.so_data.size(), prepared.region.external_inputs.size(), |
| 605 | + prepared.region.external_outputs.size()); | ||
| 636 | return fused_node; | 606 | return fused_node; |
| 637 | } | 607 | } |
| 638 | 608 | ||
| @@ -671,9 +641,12 @@ bool ReplaceFusedNodeOutputs(const ComputeGraphPtr &graph, const PreparedFusionR | |||
| 671 | return true; | 641 | return true; |
| 672 | } | 642 | } |
| 673 | 643 | ||
| 674 | -bool AddPreparedFusionNode(const ComputeGraphPtr &graph, const PreparedFusionRegion &prepared, | 644 | +bool AddPreparedFusionNode(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph, |
| 675 | - std::vector<NodePtr> &fused_nodes, std::vector<ReplacedFusionOutput> &replaced_outputs) { | 645 | + const PreparedFusionRegion &prepared, std::vector<NodePtr> &fused_nodes, |
| 676 | - const auto fused_node = CreateFusedNode(graph, prepared); | 646 | + std::vector<std::string> &root_graph_so_keys, |
| 647 | + std::vector<ReplacedFusionOutput> &replaced_outputs) { | ||
| 648 | + std::string so_key; | ||
| 649 | + const auto fused_node = CreateAndRegisterFusedNode(graph, root_graph, prepared, root_graph_so_keys, so_key); | ||
| 677 | if (fused_node == nullptr) { | 650 | if (fused_node == nullptr) { |
| 678 | return false; | 651 | return false; |
| 679 | } | 652 | } |
| @@ -712,107 +685,6 @@ bool RemoveOriginalFusionNodes(const ComputeGraphPtr &graph, const std::vector<P | |||
| 712 | return true; | 685 | return true; |
| 713 | } | 686 | } |
| 714 | 687 | ||
| 715 | -struct FusionCustomOpArtifacts { | ||
| 716 | - std::vector<std::string> inserted_so_keys; | ||
| 717 | - std::vector<AscendString> registered_op_types; | ||
| 718 | -}; | ||
| 719 | - | ||
| 720 | -OpSoBinPtr CreateFusionCustomOpSoBin(const PreparedFusionRegion &prepared) { | ||
| 721 | - const auto &so_data = prepared.codegen.so_data; | ||
| 722 | - if (so_data.empty() || (so_data.size() > std::numeric_limits<uint32_t>::max())) { | ||
| 723 | - GELOGE(PARAM_INVALID, "Invalid generated HostCPU custom-op SO size[%zu], op_type[%s].", so_data.size(), | ||
| 724 | - prepared.codegen.register_name.c_str()); | ||
| 725 | - return nullptr; | ||
| 726 | - } | ||
| 727 | - auto data = std::make_unique<char_t[]>(so_data.size()); | ||
| 728 | - std::copy(so_data.cbegin(), so_data.cend(), data.get()); | ||
| 729 | - const std::string so_name = "lib" + prepared.codegen.register_name + ".so"; | ||
| 730 | - return MakeShared<OpSoBin>(so_name, kFusedHostCpuSoVendor, std::move(data), static_cast<uint32_t>(so_data.size()), | ||
| 731 | - SoBinType::kCustomOp); | ||
| 732 | -} | ||
| 733 | - | ||
| 734 | -bool IsSameSoBin(const OpSoBinPtr &lhs, const OpSoBinPtr &rhs) { | ||
| 735 | - return (lhs != nullptr) && (rhs != nullptr) && (lhs->GetSoBinType() == rhs->GetSoBinType()) && | ||
| 736 | - (lhs->GetBinDataSize() == rhs->GetBinDataSize()) && | ||
| 737 | - std::equal(lhs->GetBinData(), lhs->GetBinData() + lhs->GetBinDataSize(), rhs->GetBinData()); | ||
| 738 | -} | ||
| 739 | - | ||
| 740 | -void RollbackFusionCustomOpArtifacts(const ComputeGraphPtr &root_graph, const FusionCustomOpArtifacts &artifacts) { | ||
| 741 | - if (!artifacts.registered_op_types.empty()) { | ||
| 742 | - CustomOpFactory::RemoveCustomOps(artifacts.registered_op_types); | ||
| 743 | - } | ||
| 744 | - if (artifacts.inserted_so_keys.empty()) { | ||
| 745 | - return; | ||
| 746 | - } | ||
| 747 | - auto so_buffer = root_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>(kSoBufferAttr); | ||
| 748 | - if (so_buffer == nullptr) { | ||
| 749 | - return; | ||
| 750 | - } | ||
| 751 | - auto updated_buffer = *so_buffer; | ||
| 752 | - for (const auto &key : artifacts.inserted_so_keys) { | ||
| 753 | - (void)updated_buffer.erase(key); | ||
| 754 | - } | ||
| 755 | - if (updated_buffer.empty()) { | ||
| 756 | - (void)root_graph->DelExtAttr(kSoBufferAttr); | ||
| 757 | - } else if (!root_graph->SetExtAttr(kSoBufferAttr, updated_buffer)) { | ||
| 758 | - GELOGW("Failed to restore custom-op SO buffer while rolling back HostCPU fusion for graph[%s].", | ||
| 759 | - root_graph->GetName().c_str()); | ||
| 760 | - } | ||
| 761 | -} | ||
| 762 | - | ||
| 763 | -Status PrepareFusionCustomOpArtifacts(const ComputeGraphPtr &root_graph, | ||
| 764 | - const std::vector<PreparedFusionRegion> &prepared_regions, | ||
| 765 | - FusionCustomOpArtifacts &artifacts) { | ||
| 766 | - artifacts = {}; | ||
| 767 | - std::map<std::string, OpSoBinPtr> updated_buffer; | ||
| 768 | - const auto current_buffer = root_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>(kSoBufferAttr); | ||
| 769 | - if (current_buffer != nullptr) { | ||
| 770 | - updated_buffer = *current_buffer; | ||
| 771 | - } | ||
| 772 | - | ||
| 773 | - std::vector<OpSoBinPtr> bins_to_load; | ||
| 774 | - const auto registry = CustomOpFactory::GetGlobalRegistryPtr(); | ||
| 775 | - GE_CHECK_NOTNULL(registry); | ||
| 776 | - for (const auto &prepared : prepared_regions) { | ||
| 777 | - const auto so_bin = CreateFusionCustomOpSoBin(prepared); | ||
| 778 | - GE_CHECK_NOTNULL(so_bin); | ||
| 779 | - const std::string so_key = so_bin->GetVendorName() + "/" + so_bin->GetSoName(); | ||
| 780 | - const auto existing = updated_buffer.find(so_key); | ||
| 781 | - if ((existing != updated_buffer.end()) && !IsSameSoBin(existing->second, so_bin)) { | ||
| 782 | - GELOGE(PARAM_INVALID, "HostCPU fusion custom-op SO key[%s] maps to different contents.", so_key.c_str()); | ||
| 783 | - return PARAM_INVALID; | ||
| 784 | - } | ||
| 785 | - if (existing == updated_buffer.end()) { | ||
| 786 | - updated_buffer.emplace(so_key, so_bin); | ||
| 787 | - artifacts.inserted_so_keys.emplace_back(so_key); | ||
| 788 | - } | ||
| 789 | - const AscendString op_type(prepared.codegen.register_name.c_str()); | ||
| 790 | - if (!registry->HasCreator(op_type, OpBackend::kHostCPU)) { | ||
| 791 | - bins_to_load.emplace_back(so_bin); | ||
| 792 | - artifacts.registered_op_types.emplace_back(op_type); | ||
| 793 | - } | ||
| 794 | - } | ||
| 795 | - | ||
| 796 | - if (!bins_to_load.empty()) { | ||
| 797 | - std::vector<CustomOpSoHandlePtr> handles; | ||
| 798 | - GE_CHK_STATUS_RET(CustomOpSoLoader::GetInstance().LoadCustomOpSoBins(bins_to_load, handles), | ||
| 799 | - "Failed to load generated HostCPU custom-op SOs."); | ||
| 800 | - const auto status = CustomOpRegistryBuilder::AddCreatorsFromSoHandles(handles, registry); | ||
| 801 | - if (status != SUCCESS) { | ||
| 802 | - GELOGE(status, "Failed to register generated HostCPU custom-op creators."); | ||
| 803 | - artifacts.registered_op_types.clear(); | ||
| 804 | - return status; | ||
| 805 | - } | ||
| 806 | - } | ||
| 807 | - if (!root_graph->SetExtAttr(kSoBufferAttr, updated_buffer)) { | ||
| 808 | - CustomOpFactory::RemoveCustomOps(artifacts.registered_op_types); | ||
| 809 | - artifacts.registered_op_types.clear(); | ||
| 810 | - GELOGE(FAILED, "Failed to save generated HostCPU custom-op SOs on root graph[%s].", root_graph->GetName().c_str()); | ||
| 811 | - return FAILED; | ||
| 812 | - } | ||
| 813 | - return SUCCESS; | ||
| 814 | -} | ||
| 815 | - | ||
| 816 | Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<PreparedFusionRegion> &prepared_regions, | 688 | Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<PreparedFusionRegion> &prepared_regions, |
| 817 | NodeEngineMap &node_atomic_engine_map, NodeEngineMap &node_composite_engine_map) { | 689 | NodeEngineMap &node_atomic_engine_map, NodeEngineMap &node_composite_engine_map) { |
| 818 | const auto root_graph = GraphUtils::FindRootGraph(graph); | 690 | const auto root_graph = GraphUtils::FindRootGraph(graph); |
| @@ -820,23 +692,19 @@ Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<Prepa | |||
| 820 | GELOGE(FAILED, "Failed to find root graph when committing HostCPU fusion for graph %s.", graph->GetName().c_str()); | 692 | GELOGE(FAILED, "Failed to find root graph when committing HostCPU fusion for graph %s.", graph->GetName().c_str()); |
| 821 | return FAILED; | 693 | return FAILED; |
| 822 | } | 694 | } |
| 823 | - FusionCustomOpArtifacts artifacts; | ||
| 824 | - GE_CHK_STATUS_RET(PrepareFusionCustomOpArtifacts(root_graph, prepared_regions, artifacts), | ||
| 825 | - "Failed to prepare HostCPU fusion custom-op artifacts for graph[%s].", graph->GetName().c_str()); | ||
| 826 | std::vector<NodePtr> fused_nodes; | 695 | std::vector<NodePtr> fused_nodes; |
| 696 | + std::vector<std::string> root_graph_so_keys; | ||
| 827 | std::vector<ReplacedFusionOutput> replaced_outputs; | 697 | std::vector<ReplacedFusionOutput> replaced_outputs; |
| 828 | GELOGD("HostCPU fusion starts graph commit: graph[%s], regions=%zu.", graph->GetName().c_str(), | 698 | GELOGD("HostCPU fusion starts graph commit: graph[%s], regions=%zu.", graph->GetName().c_str(), |
| 829 | prepared_regions.size()); | 699 | prepared_regions.size()); |
| 830 | for (const auto &prepared : prepared_regions) { | 700 | for (const auto &prepared : prepared_regions) { |
| 831 | - if (!AddPreparedFusionNode(graph, prepared, fused_nodes, replaced_outputs)) { | 701 | + if (!AddPreparedFusionNode(graph, root_graph, prepared, fused_nodes, root_graph_so_keys, replaced_outputs)) { |
| 832 | - (void)RollbackFusionCommit(graph, fused_nodes, replaced_outputs); | 702 | + (void)RollbackFusionCommit(graph, root_graph, fused_nodes, replaced_outputs, root_graph_so_keys); |
| 833 | - RollbackFusionCustomOpArtifacts(root_graph, artifacts); | ||
| 834 | return FAILED; | 703 | return FAILED; |
| 835 | } | 704 | } |
| 836 | } | 705 | } |
| 837 | if (!ValidateFusionGraph(graph, "transition")) { | 706 | if (!ValidateFusionGraph(graph, "transition")) { |
| 838 | - (void)RollbackFusionCommit(graph, fused_nodes, replaced_outputs); | 707 | + (void)RollbackFusionCommit(graph, root_graph, fused_nodes, replaced_outputs, root_graph_so_keys); |
| 839 | - RollbackFusionCustomOpArtifacts(root_graph, artifacts); | ||
| 840 | return FAILED; | 708 | return FAILED; |
| 841 | } | 709 | } |
| 842 | GELOGD("HostCPU fusion transition graph validation passed: graph[%s], fused_nodes=%zu.", graph->GetName().c_str(), | 710 | GELOGD("HostCPU fusion transition graph validation passed: graph[%s], fused_nodes=%zu.", graph->GetName().c_str(), |
| @@ -846,8 +714,8 @@ Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<Prepa | |||
| 846 | return FAILED; | 714 | return FAILED; |
| 847 | } | 715 | } |
| 848 | for (const auto &node : fused_nodes) { | 716 | for (const auto &node : fused_nodes) { |
| 849 | - node_atomic_engine_map[node] = kEngineNameCustom; | 717 | + node_atomic_engine_map[node] = kHostCpuEngineName; |
| 850 | - node_composite_engine_map[node] = kEngineNameCustom; | 718 | + node_composite_engine_map[node] = kHostCpuEngineName; |
| 851 | } | 719 | } |
| 852 | if (!ValidateFusionGraph(graph, "final")) { | 720 | if (!ValidateFusionGraph(graph, "final")) { |
| 853 | return FAILED; | 721 | return FAILED; |
| @@ -866,7 +734,7 @@ HostCpuFusionPass::HostCpuFusionPass(std::shared_ptr<HostCpuFusionCompiler> comp | |||
| 866 | } | 734 | } |
| 867 | if (op_support_checker_ == nullptr) { | 735 | if (op_support_checker_ == nullptr) { |
| 868 | op_support_checker_ = [](const std::string &op_type) { | 736 | op_support_checker_ = [](const std::string &op_type) { |
| 869 | - return HostCpuEngine::GetInstance().IsHostKernelSupported(op_type); | 737 | + return HostCpuEngine::GetInstance().IsFusedCpuKernelSupported(op_type); |
| 870 | }; | 738 | }; |
| 871 | } | 739 | } |
| 872 | } | 740 | } |
| @@ -12,11 +12,11 @@ | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | namespace ge { | 14 | namespace ge { |
| 15 | -// Compiler 和 RT2 通过这些属性识别由 HostCPU 融合生成的普通 HostCPU 自定义算子。 | 15 | +// Compiler、HostCPU Builder 和 RT2 通过这些属性传递 FusedHostCpu 内部序列化信息。 |
| 16 | constexpr char kFusedHostCpuOpType[] = "FusedHostCpu"; | 16 | constexpr char kFusedHostCpuOpType[] = "FusedHostCpu"; |
| 17 | constexpr char kFusedHostCpuRegisterName[] = "_host_cpu_fusion_register_name"; | 17 | constexpr char kFusedHostCpuRegisterName[] = "_host_cpu_fusion_register_name"; |
| 18 | -constexpr char kFusedHostCpuGenerated[] = "_host_cpu_fusion_generated"; | 18 | +constexpr char kFusedHostCpuSoKey[] = "_host_cpu_fusion_so_key"; |
| 19 | -constexpr char kFusedHostCpuSoVendor[] = "host_cpu_fusion"; | 19 | +constexpr char kFusedHostCpuSoDataPrefix[] = "_hostcpu_codegen_so_data_"; |
| 20 | constexpr char kFusedHostCpuOriginalNodes[] = "_host_cpu_fusion_original_nodes"; | 20 | constexpr char kFusedHostCpuOriginalNodes[] = "_host_cpu_fusion_original_nodes"; |
| 21 | constexpr char kFusedHostCpuOriginalTypes[] = "_host_cpu_fusion_original_types"; | 21 | constexpr char kFusedHostCpuOriginalTypes[] = "_host_cpu_fusion_original_types"; |
| 22 | constexpr char kFusedHostCpuOutputRefs[] = "_host_cpu_fusion_output_refs"; | 22 | constexpr char kFusedHostCpuOutputRefs[] = "_host_cpu_fusion_output_refs"; |
| @@ -29,7 +29,11 @@ | |||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | + | ||
| 32 | 33 | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 33 | 37 | ||
| 34 | namespace gert { | 38 | namespace gert { |
| 35 | namespace { | 39 | namespace { |
| @@ -242,11 +246,133 @@ LowerResult LoweringAiCpuCCNode(const ge::NodePtr &node, const LowerInput &lower | |||
| 242 | return {HyperStatus::Success(), {cc_launch_holder, launch_holder}, node_output.shapes, out_addrs}; | 246 | return {HyperStatus::Success(), {cc_launch_holder, launch_holder}, node_output.shapes, out_addrs}; |
| 243 | } | 247 | } |
| 244 | 248 | ||
| 249 | +bool GetFusedHostCpuSoData(const ge::NodePtr &node, std::string &fused_register_name, ge::Buffer &so_data, | ||
| 250 | + const char *&error_message, std::string &so_key, ge::ComputeGraphPtr &root_graph) { | ||
| 251 | + error_message = "Load fused HostCPU kernel failed"; | ||
| 252 | + if (!ge::AttrUtils::GetStr(node->GetOpDescBarePtr(), ge::kFusedHostCpuRegisterName, fused_register_name)) { | ||
| 253 | + error_message = "Load fused HostCPU kernel failed"; | ||
| 254 | + GELOGE(ge::INTERNAL_ERROR, "Load fused HostCPU kernel failed for node %s: register name is missing.", | ||
| 255 | + node->GetNamePtr()); | ||
| 256 | + return false; | ||
| 257 | + } | ||
| 258 | + if (!ge::AttrUtils::GetStr(node->GetOpDescBarePtr(), ge::kFusedHostCpuSoKey, so_key)) { | ||
| 259 | + error_message = "Load fused HostCPU kernel failed"; | ||
| 260 | + GELOGE(ge::INTERNAL_ERROR, "Load fused HostCPU kernel failed for node %s: so key is missing.", node->GetNamePtr()); | ||
| 261 | + return false; | ||
| 262 | + } | ||
| 263 | + const auto owner_graph = node->GetOwnerComputeGraph(); | ||
| 264 | + root_graph = ge::GraphUtils::FindRootGraph(owner_graph); | ||
| 265 | + if (root_graph == nullptr) { | ||
| 266 | + error_message = "Load fused HostCPU kernel failed"; | ||
| 267 | + GELOGE(ge::INTERNAL_ERROR, "Load fused HostCPU kernel failed for node %s: root graph was not found.", | ||
| 268 | + node->GetNamePtr()); | ||
| 269 | + return false; | ||
| 270 | + } | ||
| 271 | + if (!ge::AttrUtils::GetBytes(root_graph, so_key, so_data)) { | ||
| 272 | + error_message = "Load fused HostCPU kernel failed"; | ||
| 273 | + GELOGE(ge::INTERNAL_ERROR, | ||
| 274 | + "Load fused HostCPU kernel failed for node %s: so key[%s] was not found in root graph[%s], " | ||
| 275 | + "owner graph[%s].", | ||
| 276 | + node->GetNamePtr(), so_key.c_str(), root_graph->GetName().c_str(), | ||
| 277 | + owner_graph == nullptr ? "null" : owner_graph->GetName().c_str()); | ||
| 278 | + return false; | ||
| 279 | + } | ||
| 280 | + return true; | ||
| 281 | +} | ||
| 282 | + | ||
| 283 | +bool LoadFusedHostCpuKernel(const ge::NodePtr &node, std::string &fused_register_name, | ||
| 284 | + FusedHostCpuKernelFunctions &kernel_funcs, void *&fused_kernel_state, | ||
| 285 | + const char *&error_message) { | ||
| 286 | + std::string so_key; | ||
| 287 | + ge::Buffer so_data; | ||
| 288 | + ge::ComputeGraphPtr root_graph; | ||
| 289 | + if (!GetFusedHostCpuSoData(node, fused_register_name, so_data, error_message, so_key, root_graph)) { | ||
| 290 | + return false; | ||
| 291 | + } | ||
| 292 | + GELOGD("Load fused HostCPU kernel for node[%s]: register_name[%s], so_key[%s], so_graph[%s], so_size=%zu.", | ||
| 293 | + node->GetNamePtr(), fused_register_name.c_str(), so_key.c_str(), root_graph->GetName().c_str(), | ||
| 294 | + so_data.GetSize()); | ||
| 295 | + auto &resource_manager = AicpuResourceManager::GetInstance(); | ||
| 296 | + if (resource_manager.LoadFusedHostCpuSo(fused_register_name, so_data.GetData(), so_data.GetSize()) != | ||
| 297 | + ge::GRAPH_SUCCESS) { | ||
| 298 | + GELOGE(ge::INTERNAL_ERROR, "Load fused HostCPU kernel failed for node %s.", node->GetNamePtr()); | ||
| 299 | + return false; | ||
| 300 | + } | ||
| 301 | + kernel_funcs = resource_manager.GetFusedHostCpuKernelFunctions(fused_register_name); | ||
| 302 | + if ((kernel_funcs.create_func == nullptr) || (kernel_funcs.destroy_func == nullptr) || | ||
| 303 | + (kernel_funcs.run_func == nullptr)) { | ||
| 304 | + error_message = "Resolve fused HostCPU entry failed"; | ||
| 305 | + GELOGE(ge::INTERNAL_ERROR, "Resolve fused HostCPU private entry failed for node %s.", node->GetNamePtr()); | ||
| 306 | + return false; | ||
| 307 | + } | ||
| 308 | + fused_kernel_state = kernel_funcs.create_func(); | ||
| 309 | + if (fused_kernel_state == nullptr) { | ||
| 310 | + error_message = "Prepare fused HostCPU state failed"; | ||
| 311 | + (void)resource_manager.ReleaseFusedHostCpuSo(fused_register_name); | ||
| 312 | + GELOGE(ge::INTERNAL_ERROR, "Prepare fused HostCPU execution state failed for node %s.", node->GetNamePtr()); | ||
| 313 | + return false; | ||
| 314 | + } | ||
| 315 | + return true; | ||
| 316 | +} | ||
| 317 | + | ||
| 318 | +void *CreateFusedHostCpuComputeState(const ge::NodePtr &node, const size_t in_num, const size_t io_num, | ||
| 319 | + const std::string &fused_register_name, | ||
| 320 | + const FusedHostCpuKernelFunctions &kernel_funcs, void *fused_kernel_state) { | ||
| 321 | + std::vector<FusedHostCpuTensorMeta> tensor_metas; | ||
| 322 | + tensor_metas.reserve(io_num); | ||
| 323 | + for (size_t i = 0U; i < in_num; ++i) { | ||
| 324 | + const ge::GeTensorDesc desc = node->GetOpDescBarePtr()->GetInputDesc(i); | ||
| 325 | + tensor_metas.emplace_back(FusedHostCpuTensorMeta{desc.GetShape().GetDimNum()}); | ||
| 326 | + } | ||
| 327 | + for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) { | ||
| 328 | + const ge::GeTensorDesc desc = node->GetOpDescBarePtr()->GetOutputDesc(i); | ||
| 329 | + tensor_metas.emplace_back(FusedHostCpuTensorMeta{desc.GetShape().GetDimNum()}); | ||
| 330 | + } | ||
| 331 | + void *fused_compute_state = | ||
| 332 | + kernel::CreateFusedHostCpuComputeState(fused_register_name.c_str(), fused_kernel_state, kernel_funcs.destroy_func, | ||
| 333 | + kernel_funcs.run_func, tensor_metas.data(), tensor_metas.size()); | ||
| 334 | + if (fused_compute_state == nullptr) { | ||
| 335 | + kernel_funcs.destroy_func(fused_kernel_state); | ||
| 336 | + (void)AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(fused_register_name); | ||
| 337 | + GELOGE(ge::INTERNAL_ERROR, "Prepare fused HostCPU compute state failed for node %s.", node->GetNamePtr()); | ||
| 338 | + return nullptr; | ||
| 339 | + } | ||
| 340 | + const FusedHostCpuDestroyMeta destroy_meta = {fused_compute_state}; | ||
| 341 | + bg::FrameSelector::OnDeInitRoot([destroy_meta]() -> std::vector<bg::ValueHolderPtr> { | ||
| 342 | + auto meta_holder = bg::ValueHolder::CreateConst(&destroy_meta, sizeof(destroy_meta)); | ||
| 343 | + return {bg::ValueHolder::CreateVoidGuarder("ReleaseFusedHostCpuKernelState", meta_holder, {})}; | ||
| 344 | + }); | ||
| 345 | + bg::FrameSelector::OnDeInitRoot([fused_register_name]() -> std::vector<bg::ValueHolderPtr> { | ||
| 346 | + auto name_holder = bg::ValueHolder::CreateConst(fused_register_name.c_str(), fused_register_name.size() + 1U, true); | ||
| 347 | + return {bg::ValueHolder::CreateVoidGuarder("ReleaseFusedHostCpuSo", name_holder, {})}; | ||
| 348 | + }); | ||
| 349 | + GELOGD("Fused HostCPU kernel[%s] is ready for node[%s].", fused_register_name.c_str(), node->GetNamePtr()); | ||
| 350 | + return fused_compute_state; | ||
| 351 | +} | ||
| 352 | + | ||
| 353 | +void *PrepareFusedHostCpuComputeState(const ge::NodePtr &node, const size_t in_num, const size_t io_num, | ||
| 354 | + std::string &fused_register_name, const char *&error_message) { | ||
| 355 | + FusedHostCpuKernelFunctions kernel_funcs; | ||
| 356 | + void *fused_kernel_state = nullptr; | ||
| 357 | + if (!LoadFusedHostCpuKernel(node, fused_register_name, kernel_funcs, fused_kernel_state, error_message)) { | ||
| 358 | + return nullptr; | ||
| 359 | + } | ||
| 360 | + void *fused_compute_state = | ||
| 361 | + CreateFusedHostCpuComputeState(node, in_num, io_num, fused_register_name, kernel_funcs, fused_kernel_state); | ||
| 362 | + if (fused_compute_state == nullptr) { | ||
| 363 | + error_message = "Prepare fused HostCPU compute state failed"; | ||
| 364 | + } | ||
| 365 | + return fused_compute_state; | ||
| 366 | +} | ||
| 367 | + | ||
| 245 | struct HostAiCpuLoweringData { | 368 | struct HostAiCpuLoweringData { |
| 246 | const domi::KernelDef *kernel_def = nullptr; | 369 | const domi::KernelDef *kernel_def = nullptr; |
| 247 | bg::ValueHolderPtr session_id; | 370 | bg::ValueHolderPtr session_id; |
| 248 | bg::AicpuArgs aicpu_args; | 371 | bg::AicpuArgs aicpu_args; |
| 249 | size_t in_num = 0U; | 372 | size_t in_num = 0U; |
| 373 | + bool is_fused_host_cpu = false; | ||
| 374 | + std::string fused_register_name; | ||
| 375 | + void *fused_compute_state = nullptr; | ||
| 250 | }; | 376 | }; |
| 251 | 377 | ||
| 252 | const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &lower_input, | 378 | const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &lower_input, |
| @@ -258,6 +384,18 @@ const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput & | |||
| 258 | } | 384 | } |
| 259 | lowering_data.kernel_def = &task_def->kernel(); | 385 | lowering_data.kernel_def = &task_def->kernel(); |
| 260 | lowering_data.session_id = bg::GetSessionId(*lower_input.global_data); | 386 | lowering_data.session_id = bg::GetSessionId(*lower_input.global_data); |
| 387 | + lowering_data.is_fused_host_cpu = node->GetType() == ge::kFusedHostCpuOpType; | ||
| 388 | + if (lowering_data.is_fused_host_cpu) { | ||
| 389 | + GELOGD("Lower fused HostCPU node[%s]: inputs=%zu, outputs=%zu.", node->GetNamePtr(), | ||
| 390 | + node->GetAllInDataAnchorsSize(), node->GetAllOutDataAnchorsSize()); | ||
| 391 | + } | ||
| 392 | + | ||
| 393 | + // 融合 so 只注册编排 kernel,原始 HostCPU kernel 仍由基础库提供,必须先加载基础库。 | ||
| 394 | + if (lowering_data.is_fused_host_cpu && | ||
| 395 | + (AicpuResourceManager::GetInstance().LoadConstantFoldingLib() != ge::GRAPH_SUCCESS)) { | ||
| 396 | + GELOGE(ge::INTERNAL_ERROR, "Load HostCPU base library failed for fused node %s.", node->GetNamePtr()); | ||
| 397 | + return "Load HostCPU base library failed"; | ||
| 398 | + } | ||
| 261 | 399 | ||
| 262 | // alloc args | 400 | // alloc args |
| 263 | lowering_data.in_num = node->GetInDataNodesAndAnchors().size(); | 401 | lowering_data.in_num = node->GetInDataNodesAndAnchors().size(); |
| @@ -270,6 +408,15 @@ const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput & | |||
| 270 | } | 408 | } |
| 271 | const auto io_num = lowering_data.in_num + node->GetAllOutDataAnchorsSize(); | 409 | const auto io_num = lowering_data.in_num + node->GetAllOutDataAnchorsSize(); |
| 272 | lowering_data.aicpu_args = bg::BuildHostCCAicpuArg(node, *lowering_data.kernel_def, io_num, lowering_data.session_id); | 410 | lowering_data.aicpu_args = bg::BuildHostCCAicpuArg(node, *lowering_data.kernel_def, io_num, lowering_data.session_id); |
| 411 | + | ||
| 412 | + if (lowering_data.is_fused_host_cpu) { | ||
| 413 | + const char *fused_state_error = nullptr; | ||
| 414 | + lowering_data.fused_compute_state = PrepareFusedHostCpuComputeState( | ||
| 415 | + node, lowering_data.in_num, io_num, lowering_data.fused_register_name, fused_state_error); | ||
| 416 | + if (lowering_data.fused_compute_state == nullptr) { | ||
| 417 | + return fused_state_error; | ||
| 418 | + } | ||
| 419 | + } | ||
| 273 | return nullptr; | 420 | return nullptr; |
| 274 | } | 421 | } |
| 275 | 422 | ||
| @@ -281,6 +428,12 @@ LowerResult BuildHostAiCpuLoweringResult(const ge::NodePtr &node, const LowerInp | |||
| 281 | 428 | ||
| 282 | std::vector<bg::DevMemValueHolderPtr> output_addrs; | 429 | std::vector<bg::DevMemValueHolderPtr> output_addrs; |
| 283 | const bg::IoInfo io_info{lower_input.input_addrs, lower_input.input_shapes, output_sizes, output_shapes}; | 430 | const bg::IoInfo io_info{lower_input.input_addrs, lower_input.input_shapes, output_sizes, output_shapes}; |
| 431 | + if (lowering_data.is_fused_host_cpu) { | ||
| 432 | + auto compute_holder = bg::BuildFusedHostCpuComputeNode(node, lowering_data.fused_compute_state, io_info, | ||
| 433 | + *lower_input.global_data, output_addrs); | ||
| 434 | + SetReleaseAfter(lower_input.input_addrs, compute_holder); | ||
| 435 | + return {HyperStatus::Success(), {}, output_shapes, output_addrs}; | ||
| 436 | + } | ||
| 284 | auto compute_holder = | 437 | auto compute_holder = |
| 285 | bg::AicpuHostCompute(node, lowering_data.aicpu_args, io_info, *lower_input.global_data, output_addrs); | 438 | bg::AicpuHostCompute(node, lowering_data.aicpu_args, io_info, *lower_input.global_data, output_addrs); |
| 286 | 439 | ||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | + | ||
| 13 | 14 | ||
| 14 | 15 | ||
| 15 | 16 | ||
| @@ -22,6 +23,7 @@ | |||
| 22 | 23 | ||
| 23 | 24 | ||
| 24 | 25 | ||
| 26 | + | ||
| 25 | 27 | ||
| 26 | namespace gert { | 28 | namespace gert { |
| 27 | namespace bg { | 29 | namespace bg { |
| @@ -45,6 +47,7 @@ DevMemValueHolderPtr AllocHostCpuOutputMemory(const ge::NodePtr &node, const IoI | |||
| 45 | inputs.insert(inputs.cend(), io_info.input_addrs.cbegin(), io_info.input_addrs.cend()); | 47 | inputs.insert(inputs.cend(), io_info.input_addrs.cbegin(), io_info.input_addrs.cend()); |
| 46 | auto output = DevMemValueHolder::CreateSingleDataOutput("AllocHostCpuOutputMemory", inputs, | 48 | auto output = DevMemValueHolder::CreateSingleDataOutput("AllocHostCpuOutputMemory", inputs, |
| 47 | node->GetOpDescBarePtr()->GetStreamId()); | 49 | node->GetOpDescBarePtr()->GetStreamId()); |
| 50 | + GE_ASSERT_NOTNULL(output); | ||
| 48 | output->SetPlacement(kOnHost); | 51 | output->SetPlacement(kOnHost); |
| 49 | return output; | 52 | return output; |
| 50 | } | 53 | } |
| @@ -269,5 +272,46 @@ ValueHolderPtr AicpuHostCompute(const ge::NodePtr &node, const AicpuArgs &args, | |||
| 269 | } | 272 | } |
| 270 | return compute_holder; | 273 | return compute_holder; |
| 271 | } | 274 | } |
| 275 | + | ||
| 276 | +ValueHolderPtr BuildFusedHostCpuComputeNode(const ge::NodePtr &node, void *compute_state, const IoInfo &io_info, | ||
| 277 | + LoweringGlobalData &global_data, | ||
| 278 | + std::vector<DevMemValueHolderPtr> &output_addrs) { | ||
| 279 | + GE_ASSERT_NOTNULL(node); | ||
| 280 | + GE_ASSERT_NOTNULL(compute_state); | ||
| 281 | + const auto op_desc = node->GetOpDescBarePtr(); | ||
| 282 | + GE_ASSERT_NOTNULL(op_desc); | ||
| 283 | + GE_ASSERT_TRUE(io_info.input_shapes.size() == io_info.input_addrs.size()); | ||
| 284 | + GE_ASSERT_TRUE(io_info.output_shapes.size() == io_info.output_sizes.size()); | ||
| 285 | + | ||
| 286 | + output_addrs = AllocHostCpuOutputsMemory(node, io_info, global_data); | ||
| 287 | + GE_ASSERT_TRUE(io_info.output_shapes.size() == output_addrs.size()); | ||
| 288 | + | ||
| 289 | + const size_t input_num = io_info.input_shapes.size(); | ||
| 290 | + const size_t output_num = io_info.output_shapes.size(); | ||
| 291 | + GE_ASSERT_TRUE(input_num == op_desc->GetAllInputsSize()); | ||
| 292 | + GE_ASSERT_TRUE(output_num == op_desc->GetOutputsSize()); | ||
| 293 | + GE_ASSERT_TRUE(output_num != 0U); | ||
| 294 | + | ||
| 295 | + const FusedHostCpuComputeMeta compute_meta = {compute_state, input_num, output_num}; | ||
| 296 | + | ||
| 297 | + std::vector<ValueHolderPtr> inputs; | ||
| 298 | + inputs.emplace_back(ValueHolder::CreateConst(&compute_meta, sizeof(compute_meta))); | ||
| 299 | + inputs.insert(inputs.cend(), io_info.input_shapes.cbegin(), io_info.input_shapes.cend()); | ||
| 300 | + inputs.insert(inputs.cend(), io_info.input_addrs.cbegin(), io_info.input_addrs.cend()); | ||
| 301 | + inputs.insert(inputs.cend(), io_info.output_shapes.cbegin(), io_info.output_shapes.cend()); | ||
| 302 | + inputs.insert(inputs.cend(), output_addrs.cbegin(), output_addrs.cend()); | ||
| 303 | + | ||
| 304 | + const auto allocated_output_addrs = output_addrs; | ||
| 305 | + output_addrs = DevMemValueHolder::CreateDataOutput("FusedHostCpuCompute", inputs, output_num, op_desc->GetStreamId()); | ||
| 306 | + GE_ASSERT_EQ(output_addrs.size(), allocated_output_addrs.size()); | ||
| 307 | + for (size_t i = 0U; i < output_addrs.size(); ++i) { | ||
| 308 | + GE_ASSERT_NOTNULL(output_addrs[i]); | ||
| 309 | + GE_ASSERT_NOTNULL(allocated_output_addrs[i]); | ||
| 310 | + output_addrs[i]->SetPlacement(allocated_output_addrs[i]->GetPlacement()); | ||
| 311 | + } | ||
| 312 | + GELOGD("Build fused HostCPU private-entry compute: node[%s], inputs=%zu, outputs=%zu.", node->GetNamePtr(), input_num, | ||
| 313 | + output_num); | ||
| 314 | + return output_addrs[0U]; | ||
| 315 | +} | ||
| 272 | } // namespace bg | 316 | } // namespace bg |
| 273 | } // namespace gert | 317 | } // namespace gert |
| @@ -52,6 +52,10 @@ ValueHolderPtr AicpuHostExecFuncProcess(const AicpuHostProcFunc &func, const IoI | |||
| 52 | const std::vector<DevMemValueHolderPtr> &output_addrs); | 52 | const std::vector<DevMemValueHolderPtr> &output_addrs); |
| 53 | ValueHolderPtr AicpuHostCompute(const ge::NodePtr &node, const AicpuArgs &args, const IoInfo &io_info, | 53 | ValueHolderPtr AicpuHostCompute(const ge::NodePtr &node, const AicpuArgs &args, const IoInfo &io_info, |
| 54 | LoweringGlobalData &global_data, std::vector<DevMemValueHolderPtr> &output_addrs); | 54 | LoweringGlobalData &global_data, std::vector<DevMemValueHolderPtr> &output_addrs); |
| 55 | +// Build the ExecuteGraph node; the registered runtime kernel is FusedHostCpuCompute. | ||
| 56 | +ValueHolderPtr BuildFusedHostCpuComputeNode(const ge::NodePtr &node, void *compute_state, const IoInfo &io_info, | ||
| 57 | + LoweringGlobalData &global_data, | ||
| 58 | + std::vector<DevMemValueHolderPtr> &output_addrs); | ||
| 55 | ValueHolderPtr GetContainerIdHolder(const LowerInput &lower_input); | 59 | ValueHolderPtr GetContainerIdHolder(const LowerInput &lower_input); |
| 56 | } // namespace bg | 60 | } // namespace bg |
| 57 | } // namespace gert | 61 | } // namespace gert |
| @@ -12,6 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | + | ||
| 16 | + | ||
| 15 | 17 | ||
| 16 | 18 | ||
| 17 | 19 | ||
| @@ -29,6 +31,7 @@ | |||
| 29 | 31 | ||
| 30 | 32 | ||
| 31 | 33 | ||
| 34 | + | ||
| 32 | 35 | ||
| 33 | 36 | ||
| 34 | 37 | ||
| @@ -39,6 +42,7 @@ | |||
| 39 | 42 | ||
| 40 | 43 | ||
| 41 | 44 | ||
| 45 | + | ||
| 42 | 46 | ||
| 43 | using namespace ge; | 47 | using namespace ge; |
| 44 | 48 | ||
| @@ -412,6 +416,183 @@ ge::graphStatus AicpuHostCompute(KernelContext *context) { | |||
| 412 | } | 416 | } |
| 413 | REGISTER_KERNEL(AicpuHostCompute).RunFunc(AicpuHostCompute); | 417 | REGISTER_KERNEL(AicpuHostCompute).RunFunc(AicpuHostCompute); |
| 414 | 418 | ||
| 419 | +namespace { | ||
| 420 | +struct FusedHostCpuTensorState { | ||
| 421 | + const void *data = nullptr; | ||
| 422 | + size_t data_size = 0U; | ||
| 423 | + std::vector<int64_t> dims; | ||
| 424 | + bool initialized = false; | ||
| 425 | +}; | ||
| 426 | + | ||
| 427 | +struct FusedHostCpuCallState { | ||
| 428 | + std::string register_name; | ||
| 429 | + void *kernel_state = nullptr; | ||
| 430 | + FusedHostCpuDestroyFunc destroy_func = nullptr; | ||
| 431 | + FusedHostCpuRunFunc run_func = nullptr; | ||
| 432 | + std::vector<FusedHostCpuTensorBinding> bindings; | ||
| 433 | + std::vector<FusedHostCpuTensorState> tensor_states; | ||
| 434 | +}; | ||
| 435 | + | ||
| 436 | +bool HasSameShape(const gert::Shape &shape, const FusedHostCpuTensorState &state) { | ||
| 437 | + if (state.dims.size() != shape.GetDimNum()) { | ||
| 438 | + return false; | ||
| 439 | + } | ||
| 440 | + for (size_t i = 0U; i < shape.GetDimNum(); ++i) { | ||
| 441 | + if (state.dims[i] != shape.GetDim(i)) { | ||
| 442 | + return false; | ||
| 443 | + } | ||
| 444 | + } | ||
| 445 | + return true; | ||
| 446 | +} | ||
| 447 | + | ||
| 448 | +ge::graphStatus BuildFusedHostCpuBinding(const StorageShape *storage_shape, GertTensorData *tensor_data, | ||
| 449 | + FusedHostCpuTensorState &state, FusedHostCpuTensorBinding &binding) { | ||
| 450 | + GE_ASSERT_NOTNULL(storage_shape); | ||
| 451 | + GE_ASSERT_NOTNULL(tensor_data); | ||
| 452 | + GE_ASSERT_TRUE((tensor_data->GetSize() == 0U) || (tensor_data->GetAddr() != nullptr)); | ||
| 453 | + const auto &origin_shape = storage_shape->GetOriginShape(); | ||
| 454 | + const bool shape_changed = !state.initialized || !HasSameShape(origin_shape, state); | ||
| 455 | + if (shape_changed) { | ||
| 456 | + if (state.dims.size() != origin_shape.GetDimNum()) { | ||
| 457 | + state.dims.resize(origin_shape.GetDimNum()); | ||
| 458 | + } | ||
| 459 | + for (size_t i = 0U; i < state.dims.size(); ++i) { | ||
| 460 | + state.dims[i] = origin_shape.GetDim(i); | ||
| 461 | + } | ||
| 462 | + binding.dims = state.dims.data(); | ||
| 463 | + binding.dim_num = state.dims.size(); | ||
| 464 | + } | ||
| 465 | + const void *data = tensor_data->GetAddr(); | ||
| 466 | + const size_t data_size = tensor_data->GetSize(); | ||
| 467 | + const bool data_changed = !state.initialized || (state.data != data) || (state.data_size != data_size); | ||
| 468 | + if (data_changed) { | ||
| 469 | + binding.data = reinterpret_cast<uint8_t *>(tensor_data->GetAddr()); | ||
| 470 | + binding.data_size = data_size; | ||
| 471 | + state.data = data; | ||
| 472 | + state.data_size = data_size; | ||
| 473 | + } | ||
| 474 | + binding.flags = (shape_changed ? kFusedHostCpuShapeChanged : 0U) | (data_changed ? kFusedHostCpuDataChanged : 0U); | ||
| 475 | + state.initialized = true; | ||
| 476 | + return ge::GRAPH_SUCCESS; | ||
| 477 | +} | ||
| 478 | +} // namespace | ||
| 479 | + | ||
| 480 | +void *CreateFusedHostCpuComputeState(const char *register_name, void *kernel_state, | ||
| 481 | + const FusedHostCpuDestroyFunc destroy_func, const FusedHostCpuRunFunc run_func, | ||
| 482 | + const FusedHostCpuTensorMeta *tensor_metas, const size_t io_num) { | ||
| 483 | + if ((register_name == nullptr) || (kernel_state == nullptr) || (destroy_func == nullptr) || (run_func == nullptr) || | ||
| 484 | + (tensor_metas == nullptr) || (io_num == 0U)) { | ||
| 485 | + GELOGE(ge::PARAM_INVALID, | ||
| 486 | + "Invalid fused HostCPU compute state arguments: register_null[%d], kernel_state_null[%d], " | ||
| 487 | + "destroy_null[%d], run_null[%d], tensor_metas_null[%d], io_num[%zu].", | ||
| 488 | + static_cast<int32_t>(register_name == nullptr), static_cast<int32_t>(kernel_state == nullptr), | ||
| 489 | + static_cast<int32_t>(destroy_func == nullptr), static_cast<int32_t>(run_func == nullptr), | ||
| 490 | + static_cast<int32_t>(tensor_metas == nullptr), io_num); | ||
| 491 | + return nullptr; | ||
| 492 | + } | ||
| 493 | + std::unique_ptr<FusedHostCpuCallState> state = std::make_unique<FusedHostCpuCallState>(); | ||
| 494 | + state->register_name = register_name; | ||
| 495 | + state->kernel_state = kernel_state; | ||
| 496 | + state->destroy_func = destroy_func; | ||
| 497 | + state->run_func = run_func; | ||
| 498 | + state->bindings.reserve(io_num); | ||
| 499 | + state->tensor_states.reserve(io_num); | ||
| 500 | + for (size_t i = 0U; i < io_num; ++i) { | ||
| 501 | + std::vector<int64_t> dims(tensor_metas[i].dim_num, ge::UNKNOWN_DIM); | ||
| 502 | + FusedHostCpuTensorState tensor_state; | ||
| 503 | + tensor_state.dims = std::move(dims); | ||
| 504 | + state->tensor_states.emplace_back(std::move(tensor_state)); | ||
| 505 | + state->bindings.emplace_back( | ||
| 506 | + FusedHostCpuTensorBinding{state->tensor_states.back().dims.data(), nullptr, tensor_metas[i].dim_num, 0U, 0U}); | ||
| 507 | + } | ||
| 508 | + return state.release(); | ||
| 509 | +} | ||
| 510 | + | ||
| 511 | +void DestroyFusedHostCpuComputeState(void *compute_state) { | ||
| 512 | + FusedHostCpuCallState *state = static_cast<FusedHostCpuCallState *>(compute_state); | ||
| 513 | + if (state == nullptr) { | ||
| 514 | + return; | ||
| 515 | + } | ||
| 516 | + state->destroy_func(state->kernel_state); | ||
| 517 | + delete state; | ||
| 518 | +} | ||
| 519 | + | ||
| 520 | +// Runtime callback for the ExecuteGraph kernel registered as FusedHostCpuCompute. | ||
| 521 | +ge::graphStatus RunFusedHostCpuCompute(KernelContext *context) { | ||
| 522 | + GE_ASSERT_NOTNULL(context); | ||
| 523 | + const auto compute_meta = context->GetInputPointer<FusedHostCpuComputeMeta>(0U); | ||
| 524 | + GE_ASSERT_NOTNULL(compute_meta); | ||
| 525 | + FusedHostCpuCallState *call_state = static_cast<FusedHostCpuCallState *>(compute_meta->compute_state); | ||
| 526 | + GE_ASSERT_NOTNULL(call_state); | ||
| 527 | + GE_ASSERT_NOTNULL(call_state->kernel_state); | ||
| 528 | + GE_ASSERT_NOTNULL(call_state->run_func); | ||
| 529 | + const auto input_num = compute_meta->input_num; | ||
| 530 | + const auto output_num = compute_meta->output_num; | ||
| 531 | + const auto io_num = input_num + output_num; | ||
| 532 | + GE_ASSERT_TRUE(call_state->bindings.size() == io_num); | ||
| 533 | + GE_ASSERT_TRUE(call_state->tensor_states.size() == io_num); | ||
| 534 | + | ||
| 535 | + const size_t input_shape_start = 1U; | ||
| 536 | + const size_t input_addr_start = input_shape_start + input_num; | ||
| 537 | + const size_t output_shape_start = input_addr_start + input_num; | ||
| 538 | + const size_t output_addr_start = output_shape_start + output_num; | ||
| 539 | + GE_ASSERT_TRUE(context->GetInputNum() == (output_addr_start + output_num)); | ||
| 540 | + | ||
| 541 | + uint32_t binding_flags = 0U; | ||
| 542 | + for (size_t i = 0U; i < input_num; ++i) { | ||
| 543 | + const auto storage_shape = context->GetInputPointer<StorageShape>(input_shape_start + i); | ||
| 544 | + auto tensor_data = context->MutableInputPointer<GertTensorData>(input_addr_start + i); | ||
| 545 | + GE_ASSERT_SUCCESS( | ||
| 546 | + BuildFusedHostCpuBinding(storage_shape, tensor_data, call_state->tensor_states[i], call_state->bindings[i])); | ||
| 547 | + binding_flags |= call_state->bindings[i].flags; | ||
| 548 | + } | ||
| 549 | + | ||
| 550 | + for (size_t i = 0U; i < output_num; ++i) { | ||
| 551 | + const auto storage_shape = context->GetInputPointer<StorageShape>(output_shape_start + i); | ||
| 552 | + auto tensor_data = context->MutableInputPointer<GertTensorData>(output_addr_start + i); | ||
| 553 | + const size_t tensor_index = input_num + i; | ||
| 554 | + GE_ASSERT_SUCCESS(BuildFusedHostCpuBinding(storage_shape, tensor_data, call_state->tensor_states[tensor_index], | ||
| 555 | + call_state->bindings[tensor_index])); | ||
| 556 | + binding_flags |= call_state->bindings[tensor_index].flags; | ||
| 557 | + } | ||
| 558 | + | ||
| 559 | + const uint32_t ret = call_state->run_func(call_state->kernel_state, | ||
| 560 | + static_cast<const void *>(call_state->bindings.data()), binding_flags); | ||
| 561 | + GE_ASSERT_TRUE(ret == 0U, "Fused HostCPU private entry failed: register_name[%s], ret=%u.", | ||
| 562 | + call_state->register_name.c_str(), ret); | ||
| 563 | + return ge::GRAPH_SUCCESS; | ||
| 564 | +} | ||
| 565 | + | ||
| 566 | +ge::graphStatus CreateFusedHostCpuComputeOutputs(const ge::FastNode *node, KernelContext *context) { | ||
| 567 | + (void)node; | ||
| 568 | + GE_ASSERT_NOTNULL(context); | ||
| 569 | + GE_ASSERT_TRUE(context->GetInputNum() >= context->GetOutputNum()); | ||
| 570 | + const size_t output_addr_start = context->GetInputNum() - context->GetOutputNum(); | ||
| 571 | + for (size_t i = 0U; i < context->GetOutputNum(); ++i) { | ||
| 572 | + auto chain = context->GetOutput(i); | ||
| 573 | + auto tensor_data = context->MutableInputPointer<GertTensorData>(output_addr_start + i); | ||
| 574 | + GE_ASSERT_NOTNULL(chain); | ||
| 575 | + GE_ASSERT_NOTNULL(tensor_data); | ||
| 576 | + chain->Set(tensor_data, nullptr); | ||
| 577 | + } | ||
| 578 | + return ge::GRAPH_SUCCESS; | ||
| 579 | +} | ||
| 580 | + | ||
| 581 | +REGISTER_KERNEL(FusedHostCpuCompute) | ||
| 582 | + .RunFunc(RunFusedHostCpuCompute) | ||
| 583 | + .OutputsCreator(CreateFusedHostCpuComputeOutputs) | ||
| 584 | + .ConcurrentCriticalSectionKey(kKernelUseMemory); | ||
| 585 | + | ||
| 586 | +ge::graphStatus ReleaseFusedHostCpuKernelState(KernelContext *context) { | ||
| 587 | + GE_ASSERT_NOTNULL(context); | ||
| 588 | + const auto destroy_meta = context->GetInputPointer<FusedHostCpuDestroyMeta>(0U); | ||
| 589 | + GE_ASSERT_NOTNULL(destroy_meta); | ||
| 590 | + GE_ASSERT_NOTNULL(destroy_meta->compute_state); | ||
| 591 | + DestroyFusedHostCpuComputeState(destroy_meta->compute_state); | ||
| 592 | + return ge::GRAPH_SUCCESS; | ||
| 593 | +} | ||
| 594 | +REGISTER_KERNEL(ReleaseFusedHostCpuKernelState).RunFunc(ReleaseFusedHostCpuKernelState); | ||
| 595 | + | ||
| 415 | ge::graphStatus AicpuHostExecFunc(KernelContext *context) { | 596 | ge::graphStatus AicpuHostExecFunc(KernelContext *context) { |
| 416 | const auto input_size = context->GetInputNum(); | 597 | const auto input_size = context->GetInputNum(); |
| 417 | // func取输入的最后一个,因为前面输入个数不固定。 | 598 | // func取输入的最后一个,因为前面输入个数不固定。 |
| @@ -9,6 +9,8 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | + | ||
| 13 | + | ||
| 12 | 14 | ||
| 13 | 15 | ||
| 14 | 16 | ||
| @@ -23,6 +25,14 @@ | |||
| 23 | 25 | ||
| 24 | 26 | ||
| 25 | 27 | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 26 | 36 | ||
| 27 | namespace gert { | 37 | namespace gert { |
| 28 | namespace { | 38 | namespace { |
| @@ -34,6 +44,78 @@ void FreeHbmMem(void *p) { | |||
| 34 | 44 | ||
| 35 | const std::string kHostCpuLibRelativePathOld = "/op_impl/built-in/host_cpu/libconstant_folding_ops.so"; | 45 | const std::string kHostCpuLibRelativePathOld = "/op_impl/built-in/host_cpu/libconstant_folding_ops.so"; |
| 36 | const std::string kHostCpuLibRelativePath = "/built-in/op_impl/host_cpu/libconstant_folding_ops.so"; | 46 | const std::string kHostCpuLibRelativePath = "/built-in/op_impl/host_cpu/libconstant_folding_ops.so"; |
| 47 | +constexpr size_t kMaxFusedHostCpuSoSize = 10U * 1024U * 1024U; | ||
| 48 | +constexpr size_t kMaxFusedRegisterNameSize = 160U; | ||
| 49 | +constexpr char kValidateFusedHostCpuKernelRegistration[] = "ValidateFusedHostCpuKernelRegistration"; | ||
| 50 | +constexpr char kCreateFusedHostCpuKernelState[] = "CreateFusedHostCpuKernelState"; | ||
| 51 | +constexpr char kDestroyFusedHostCpuKernelState[] = "DestroyFusedHostCpuKernelState"; | ||
| 52 | +constexpr char kRunFusedHostCpuKernel[] = "RunFusedHostCpuKernel"; | ||
| 53 | + | ||
| 54 | +bool IsAsciiAlphaNumeric(const unsigned char ch) { | ||
| 55 | + return ((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')); | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +bool IsValidFusedRegisterName(const std::string ®ister_name) { | ||
| 59 | + const std::string prefix = std::string(ge::kFusedHostCpuOpType) + "_"; | ||
| 60 | + if ((register_name.size() <= prefix.size()) || (register_name.size() > kMaxFusedRegisterNameSize) || | ||
| 61 | + (register_name.compare(0U, prefix.size(), prefix) != 0)) { | ||
| 62 | + return false; | ||
| 63 | + } | ||
| 64 | + return std::all_of(register_name.cbegin() + static_cast<std::ptrdiff_t>(prefix.size()), register_name.cend(), | ||
| 65 | + [](const unsigned char ch) { return IsAsciiAlphaNumeric(ch) || (ch == '_'); }); | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +uint64_t HashFusedSo(const uint8_t *data, const size_t size) { | ||
| 69 | + uint64_t hash = 1469598103934665603ULL; | ||
| 70 | + for (size_t i = 0U; i < size; ++i) { | ||
| 71 | + hash ^= data[i]; | ||
| 72 | + hash *= 1099511628211ULL; | ||
| 73 | + } | ||
| 74 | + return hash; | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +bool IsExpectedFusedElf(const uint8_t *data, const size_t size) { | ||
| 78 | + if ((size < 20U) || (data[0] != 0x7FU) || (data[1] != 'E') || (data[2] != 'L') || (data[3] != 'F') || | ||
| 79 | + (data[4] != 2U) || (data[5] != 1U) || (data[6] != 1U) || (data[16] != 3U) || (data[17] != 0U)) { | ||
| 80 | + return false; | ||
| 81 | + } | ||
| 82 | + const uint16_t machine = static_cast<uint16_t>(data[18]) | (static_cast<uint16_t>(data[19]) << 8U); | ||
| 83 | + | ||
| 84 | + return machine == 183U; | ||
| 85 | + | ||
| 86 | + return machine == 62U; | ||
| 87 | + | ||
| 88 | + (void)machine; | ||
| 89 | + return true; | ||
| 90 | + | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +bool ValidateFusedHostCpuRegistration(void *handle, const std::string ®ister_name) { | ||
| 94 | + using ValidateRegistration = bool (*)(const char *); | ||
| 95 | + const auto validate = | ||
| 96 | + reinterpret_cast<ValidateRegistration>(mmDlsym(handle, kValidateFusedHostCpuKernelRegistration)); | ||
| 97 | + return (validate != nullptr) && validate(register_name.c_str()); | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | + | ||
| 101 | +bool WriteAll(const int fd, const uint8_t *data, const size_t size) { | ||
| 102 | + size_t offset = 0U; | ||
| 103 | + while (offset < size) { | ||
| 104 | + const ssize_t written = write(fd, data + offset, size - offset); | ||
| 105 | + if (written < 0) { | ||
| 106 | + if (errno == EINTR) { | ||
| 107 | + continue; | ||
| 108 | + } | ||
| 109 | + return false; | ||
| 110 | + } | ||
| 111 | + if (written == 0) { | ||
| 112 | + return false; | ||
| 113 | + } | ||
| 114 | + offset += static_cast<size_t>(written); | ||
| 115 | + } | ||
| 116 | + return true; | ||
| 117 | +} | ||
| 118 | + | ||
| 37 | 119 | ||
| 38 | ge::graphStatus GetRealPath(std::string &path) { | 120 | ge::graphStatus GetRealPath(std::string &path) { |
| 39 | const std::string real_path = ge::RealPath(path.c_str()); | 121 | const std::string real_path = ge::RealPath(path.c_str()); |
| @@ -72,10 +154,20 @@ AicpuResourceManager &AicpuResourceManager::GetInstance() { | |||
| 72 | } | 154 | } |
| 73 | 155 | ||
| 74 | AicpuResourceManager::~AicpuResourceManager() { | 156 | AicpuResourceManager::~AicpuResourceManager() { |
| 157 | + // CpuKernelRegister 没有注销接口,其 std::function creator 指向 JIT so。这里必须先让基础 HostCPU | ||
| 158 | + // 库在 dlclose 时销毁 registry,再由进程回收仍映射的 JIT so,不能提前 dlclose 形成悬空 creator。 | ||
| 75 | if (so_handle_ != nullptr) { | 159 | if (so_handle_ != nullptr) { |
| 76 | (void)mmDlclose(so_handle_); | 160 | (void)mmDlclose(so_handle_); |
| 77 | so_handle_ = nullptr; | 161 | so_handle_ = nullptr; |
| 78 | } | 162 | } |
| 163 | + | ||
| 164 | + for (const std::pair<const uint64_t, int> &fd_entry : fused_so_fds_) { | ||
| 165 | + (void)close(fd_entry.second); | ||
| 166 | + } | ||
| 167 | + for (const int fd : fused_quarantined_so_fds_) { | ||
| 168 | + (void)close(fd); | ||
| 169 | + } | ||
| 170 | + | ||
| 79 | } | 171 | } |
| 80 | 172 | ||
| 81 | ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() { | 173 | ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() { |
| @@ -118,6 +210,174 @@ ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() { | |||
| 118 | return ge::GRAPH_SUCCESS; | 210 | return ge::GRAPH_SUCCESS; |
| 119 | } | 211 | } |
| 120 | 212 | ||
| 213 | +ge::graphStatus AicpuResourceManager::TryReuseFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, | ||
| 214 | + const size_t so_size, const uint64_t so_hash, | ||
| 215 | + bool &handled) { | ||
| 216 | + handled = false; | ||
| 217 | + const auto register_iter = fused_register_hashes_.find(register_name); | ||
| 218 | + if (register_iter != fused_register_hashes_.end()) { | ||
| 219 | + handled = true; | ||
| 220 | + const auto content_iter = fused_so_contents_.find(so_hash); | ||
| 221 | + if ((register_iter->second != so_hash) || (content_iter == fused_so_contents_.end()) || | ||
| 222 | + (content_iter->second.size() != so_size) || | ||
| 223 | + !std::equal(content_iter->second.cbegin(), content_iter->second.cend(), so_data)) { | ||
| 224 | + GELOGE(ge::PARAM_INVALID, "Fused HostCPU register name %s maps to different shared objects.", | ||
| 225 | + register_name.c_str()); | ||
| 226 | + return ge::PARAM_INVALID; | ||
| 227 | + } | ||
| 228 | + ++fused_register_ref_counts_[register_name]; | ||
| 229 | + ++fused_so_ref_counts_[so_hash]; | ||
| 230 | + GELOGD("Reuse fused HostCPU shared object by register name[%s].", register_name.c_str()); | ||
| 231 | + return ge::GRAPH_SUCCESS; | ||
| 232 | + } | ||
| 233 | + const auto handle_iter = fused_so_handles_.find(so_hash); | ||
| 234 | + if (handle_iter == fused_so_handles_.end()) { | ||
| 235 | + return ge::GRAPH_SUCCESS; | ||
| 236 | + } | ||
| 237 | + handled = true; | ||
| 238 | + const auto content_iter = fused_so_contents_.find(so_hash); | ||
| 239 | + if ((content_iter == fused_so_contents_.end()) || (content_iter->second.size() != so_size) || | ||
| 240 | + !std::equal(content_iter->second.cbegin(), content_iter->second.cend(), so_data)) { | ||
| 241 | + GELOGE(ge::PARAM_INVALID, "Hash collision detected while loading fused HostCPU shared object %s.", | ||
| 242 | + register_name.c_str()); | ||
| 243 | + return ge::PARAM_INVALID; | ||
| 244 | + } | ||
| 245 | + GELOGE(ge::PARAM_INVALID, "Fused HostCPU shared object content is already cached by another register name %s.", | ||
| 246 | + register_name.c_str()); | ||
| 247 | + return ge::PARAM_INVALID; | ||
| 248 | +} | ||
| 249 | + | ||
| 250 | +ge::graphStatus AicpuResourceManager::LoadFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, | ||
| 251 | + const size_t so_size) { | ||
| 252 | + if (!IsValidFusedRegisterName(register_name) || (so_data == nullptr) || (so_size > kMaxFusedHostCpuSoSize) || | ||
| 253 | + !IsExpectedFusedElf(so_data, so_size)) { | ||
| 254 | + GELOGE(ge::PARAM_INVALID, "Invalid fused HostCPU shared object for register name %s.", register_name.c_str()); | ||
| 255 | + return ge::PARAM_INVALID; | ||
| 256 | + } | ||
| 257 | + const uint64_t so_hash = HashFusedSo(so_data, so_size); | ||
| 258 | + GELOGD("Load fused HostCPU shared object: register_name[%s], so_size=%zu, hash=%llu.", register_name.c_str(), so_size, | ||
| 259 | + static_cast<unsigned long long>(so_hash)); | ||
| 260 | + // 同一注册名可被多个模型复用;每次成功加载都对应模型卸载阶段的一次 Release。 | ||
| 261 | + const std::lock_guard<std::mutex> lock(fused_so_mutex_); | ||
| 262 | + bool handled = false; | ||
| 263 | + const auto reuse_status = TryReuseFusedHostCpuSo(register_name, so_data, so_size, so_hash, handled); | ||
| 264 | + if (handled) { | ||
| 265 | + return reuse_status; | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + GELOGW("Fused HostCPU shared object loading is unsupported on the current platform: register_name[%s].", | ||
| 269 | + register_name.c_str()); | ||
| 270 | + return ge::UNSUPPORTED; | ||
| 271 | + | ||
| 272 | + return LoadNewFusedHostCpuSo(register_name, so_data, so_size, so_hash); | ||
| 273 | + | ||
| 274 | +} | ||
| 275 | + | ||
| 276 | + | ||
| 277 | +ge::graphStatus AicpuResourceManager::LoadNewFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, | ||
| 278 | + const size_t so_size, const uint64_t so_hash) { | ||
| 279 | + void *handle = nullptr; | ||
| 280 | + int fd = -1; | ||
| 281 | + FusedHostCpuKernelFunctions kernel_funcs; | ||
| 282 | + if (OpenFusedHostCpuSo(register_name, so_data, so_size, handle, fd, kernel_funcs) != ge::GRAPH_SUCCESS) { | ||
| 283 | + return ge::INTERNAL_ERROR; | ||
| 284 | + } | ||
| 285 | + fused_so_handles_[so_hash] = handle; | ||
| 286 | + // glibc 会按 dlopen 路径复用已加载对象。保持 fd 存活,确保后续融合 SO 不会再次取得相同的 | ||
| 287 | + // /proc/self/fd/<fd> 路径而错误复用当前 handle。 | ||
| 288 | + fused_so_fds_[so_hash] = fd; | ||
| 289 | + fused_so_ref_counts_[so_hash] = 1U; | ||
| 290 | + fused_so_contents_[so_hash] = std::vector<uint8_t>(so_data, so_data + so_size); | ||
| 291 | + fused_register_hashes_[register_name] = so_hash; | ||
| 292 | + fused_register_ref_counts_[register_name] = 1U; | ||
| 293 | + fused_kernel_funcs_[register_name] = kernel_funcs; | ||
| 294 | + GELOGD("Fused HostCPU kernel[%s] registered successfully, cached_so_count=%zu.", register_name.c_str(), | ||
| 295 | + fused_so_handles_.size()); | ||
| 296 | + return ge::GRAPH_SUCCESS; | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +ge::graphStatus AicpuResourceManager::OpenFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, | ||
| 300 | + const size_t so_size, void *&handle, int &fd, | ||
| 301 | + FusedHostCpuKernelFunctions &kernel_funcs) { | ||
| 302 | + fd = static_cast<int>(syscall(__NR_memfd_create, "fused_host_cpu", 0U)); | ||
| 303 | + if (fd < 0) { | ||
| 304 | + GELOGE(ge::INTERNAL_ERROR, "Create memfd for fused HostCPU shared object failed, errno=%d.", errno); | ||
| 305 | + return ge::INTERNAL_ERROR; | ||
| 306 | + } | ||
| 307 | + if (!WriteAll(fd, so_data, so_size)) { | ||
| 308 | + GELOGE(ge::INTERNAL_ERROR, "Write fused HostCPU shared object failed, errno=%d.", errno); | ||
| 309 | + (void)close(fd); | ||
| 310 | + return ge::INTERNAL_ERROR; | ||
| 311 | + } | ||
| 312 | + const std::string path = "/proc/self/fd/" + std::to_string(fd); | ||
| 313 | + const auto open_flag = static_cast<uint32_t>(MMPA_RTLD_NOW) | static_cast<uint32_t>(RTLD_LOCAL); | ||
| 314 | + GELOGD("Open fused HostCPU shared object from anonymous fd[%d] for register name[%s].", fd, register_name.c_str()); | ||
| 315 | + handle = mmDlopen(path.c_str(), static_cast<int32_t>(open_flag)); | ||
| 316 | + if (handle == nullptr) { | ||
| 317 | + const ge::char_t *error = mmDlerror(); | ||
| 318 | + GELOGE(ge::INTERNAL_ERROR, "Load fused HostCPU shared object failed for %s, error=%s.", register_name.c_str(), | ||
| 319 | + (error == nullptr) ? "" : error); | ||
| 320 | + (void)close(fd); | ||
| 321 | + return ge::INTERNAL_ERROR; | ||
| 322 | + } | ||
| 323 | + if (!ValidateFusedHostCpuRegistration(handle, register_name)) { | ||
| 324 | + GELOGE(ge::INTERNAL_ERROR, "Shared object did not register fused HostCPU CpuKernel %s.", register_name.c_str()); | ||
| 325 | + fused_quarantined_so_handles_.emplace_back(handle); | ||
| 326 | + fused_quarantined_so_fds_.emplace_back(fd); | ||
| 327 | + return ge::INTERNAL_ERROR; | ||
| 328 | + } | ||
| 329 | + kernel_funcs.create_func = reinterpret_cast<FusedHostCpuCreateFunc>(mmDlsym(handle, kCreateFusedHostCpuKernelState)); | ||
| 330 | + kernel_funcs.destroy_func = | ||
| 331 | + reinterpret_cast<FusedHostCpuDestroyFunc>(mmDlsym(handle, kDestroyFusedHostCpuKernelState)); | ||
| 332 | + kernel_funcs.run_func = reinterpret_cast<FusedHostCpuRunFunc>(mmDlsym(handle, kRunFusedHostCpuKernel)); | ||
| 333 | + if ((kernel_funcs.create_func == nullptr) || (kernel_funcs.destroy_func == nullptr) || | ||
| 334 | + (kernel_funcs.run_func == nullptr)) { | ||
| 335 | + GELOGE(ge::INTERNAL_ERROR, "Shared object does not export complete private fused HostCPU entries for %s.", | ||
| 336 | + register_name.c_str()); | ||
| 337 | + fused_quarantined_so_handles_.emplace_back(handle); | ||
| 338 | + fused_quarantined_so_fds_.emplace_back(fd); | ||
| 339 | + return ge::INTERNAL_ERROR; | ||
| 340 | + } | ||
| 341 | + return ge::GRAPH_SUCCESS; | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | + | ||
| 345 | +FusedHostCpuKernelFunctions AicpuResourceManager::GetFusedHostCpuKernelFunctions(const std::string ®ister_name) { | ||
| 346 | + const std::lock_guard<std::mutex> lock(fused_so_mutex_); | ||
| 347 | + const auto iter = fused_kernel_funcs_.find(register_name); | ||
| 348 | + return (iter == fused_kernel_funcs_.end()) ? FusedHostCpuKernelFunctions() : iter->second; | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +ge::graphStatus AicpuResourceManager::ReleaseFusedHostCpuSo(const std::string ®ister_name) { | ||
| 352 | + const std::lock_guard<std::mutex> lock(fused_so_mutex_); | ||
| 353 | + const auto ref_iter = fused_register_ref_counts_.find(register_name); | ||
| 354 | + const auto hash_iter = fused_register_hashes_.find(register_name); | ||
| 355 | + if ((ref_iter == fused_register_ref_counts_.end()) || (hash_iter == fused_register_hashes_.end()) || | ||
| 356 | + (ref_iter->second == 0U)) { | ||
| 357 | + GELOGE(ge::PARAM_INVALID, "Fused HostCPU kernel %s is not owned by any loaded model.", register_name.c_str()); | ||
| 358 | + return ge::PARAM_INVALID; | ||
| 359 | + } | ||
| 360 | + const uint64_t so_hash = hash_iter->second; | ||
| 361 | + const auto so_ref_iter = fused_so_ref_counts_.find(so_hash); | ||
| 362 | + const auto handle_iter = fused_so_handles_.find(so_hash); | ||
| 363 | + if ((so_ref_iter == fused_so_ref_counts_.end()) || (so_ref_iter->second == 0U) || | ||
| 364 | + (handle_iter == fused_so_handles_.end())) { | ||
| 365 | + GELOGE(ge::INTERNAL_ERROR, "Fused HostCPU kernel %s has incomplete shared object ownership.", | ||
| 366 | + register_name.c_str()); | ||
| 367 | + return ge::INTERNAL_ERROR; | ||
| 368 | + } | ||
| 369 | + --so_ref_iter->second; | ||
| 370 | + if (--ref_iter->second > 0U) { | ||
| 371 | + GELOGD("Keep fused HostCPU kernel[%s], remaining model references=%zu.", register_name.c_str(), ref_iter->second); | ||
| 372 | + return ge::GRAPH_SUCCESS; | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + // CpuKernelRegister 不提供注销接口。creator 是定义在 JIT so 中的 std::function,引用归零后仍必须保留 | ||
| 376 | + // so 映射和内容缓存,后续模型可直接复用;进程退出时由操作系统统一回收映射。 | ||
| 377 | + GELOGD("Released model reference for fused HostCPU kernel[%s]; keep JIT so in process cache.", register_name.c_str()); | ||
| 378 | + return ge::GRAPH_SUCCESS; | ||
| 379 | +} | ||
| 380 | + | ||
| 121 | std::function<uint32_t(void *)> AicpuResourceManager::GetRunCpuKernel() const { | 381 | std::function<uint32_t(void *)> AicpuResourceManager::GetRunCpuKernel() const { |
| 122 | return run_cpu_kernel_; | 382 | return run_cpu_kernel_; |
| 123 | } | 383 | } |
| @@ -196,6 +456,14 @@ ge::graphStatus EnsureCreateTfSession(KernelContext *context) { | |||
| 196 | } | 456 | } |
| 197 | REGISTER_KERNEL(EnsureCreateTfSession).RunFunc(EnsureCreateTfSession); | 457 | REGISTER_KERNEL(EnsureCreateTfSession).RunFunc(EnsureCreateTfSession); |
| 198 | 458 | ||
| 459 | +ge::graphStatus ReleaseFusedHostCpuSo(KernelContext *context) { | ||
| 460 | + GE_ASSERT_NOTNULL(context); | ||
| 461 | + GE_ASSERT_NOTNULL(context->GetInputValue<const char *>(0U)); | ||
| 462 | + const std::string register_name(context->GetInputValue<const char *>(0U)); | ||
| 463 | + return AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(register_name); | ||
| 464 | +} | ||
| 465 | +REGISTER_KERNEL(ReleaseFusedHostCpuSo).RunFunc(ReleaseFusedHostCpuSo); | ||
| 466 | + | ||
| 199 | ge::graphStatus CreateStepId(KernelContext *context) { | 467 | ge::graphStatus CreateStepId(KernelContext *context) { |
| 200 | auto step_id = context->GetOutputPointer<void *>(0U); | 468 | auto step_id = context->GetOutputPointer<void *>(0U); |
| 201 | auto iteration = context->GetOutputPointer<int64_t>(1U); | 469 | auto iteration = context->GetOutputPointer<int64_t>(1U); |
| @@ -11,8 +11,12 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | + | ||
| 15 | + | ||
| 14 | 16 | ||
| 15 | 17 | ||
| 18 | + | ||
| 19 | + | ||
| 16 | 20 | ||
| 17 | 21 | ||
| 18 | 22 | ||
| @@ -26,6 +30,15 @@ | |||
| 26 | namespace gert { | 30 | namespace gert { |
| 27 | 31 | ||
| 28 | using AicpuHostProcFunc = ge::graphStatus (*)(KernelContext *); | 32 | using AicpuHostProcFunc = ge::graphStatus (*)(KernelContext *); |
| 33 | +using FusedHostCpuCreateFunc = void *(*)(); | ||
| 34 | +using FusedHostCpuDestroyFunc = void (*)(void *); | ||
| 35 | +using FusedHostCpuRunFunc = uint32_t (*)(void *, const void *, uint32_t); | ||
| 36 | + | ||
| 37 | +struct FusedHostCpuKernelFunctions { | ||
| 38 | + FusedHostCpuCreateFunc create_func = nullptr; | ||
| 39 | + FusedHostCpuDestroyFunc destroy_func = nullptr; | ||
| 40 | + FusedHostCpuRunFunc run_func = nullptr; | ||
| 41 | +}; | ||
| 29 | 42 | ||
| 30 | class AicpuResourceManager { | 43 | class AicpuResourceManager { |
| 31 | public: | 44 | public: |
| @@ -33,6 +46,9 @@ class AicpuResourceManager { | |||
| 33 | ~AicpuResourceManager(); | 46 | ~AicpuResourceManager(); |
| 34 | 47 | ||
| 35 | ge::graphStatus LoadConstantFoldingLib(); | 48 | ge::graphStatus LoadConstantFoldingLib(); |
| 49 | + ge::graphStatus LoadFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, size_t so_size); | ||
| 50 | + ge::graphStatus ReleaseFusedHostCpuSo(const std::string ®ister_name); | ||
| 51 | + FusedHostCpuKernelFunctions GetFusedHostCpuKernelFunctions(const std::string ®ister_name); | ||
| 36 | std::function<uint32_t(void *)> GetRunCpuKernel() const; | 52 | std::function<uint32_t(void *)> GetRunCpuKernel() const; |
| 37 | std::function<AicpuHostProcFunc(std::string)> GetAicpuHostFindFunc() const; | 53 | std::function<AicpuHostProcFunc(std::string)> GetAicpuHostFindFunc() const; |
| 38 | 54 | ||
| @@ -52,6 +68,12 @@ class AicpuResourceManager { | |||
| 52 | ge::graphStatus HasLoadedCustAicpuSo(const std::string &so_name, bool &loaded); | 68 | ge::graphStatus HasLoadedCustAicpuSo(const std::string &so_name, bool &loaded); |
| 53 | 69 | ||
| 54 | private: | 70 | private: |
| 71 | + ge::graphStatus TryReuseFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, size_t so_size, | ||
| 72 | + uint64_t so_hash, bool &handled); | ||
| 73 | + ge::graphStatus LoadNewFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, size_t so_size, | ||
| 74 | + uint64_t so_hash); | ||
| 75 | + ge::graphStatus OpenFusedHostCpuSo(const std::string ®ister_name, const uint8_t *so_data, size_t so_size, | ||
| 76 | + void *&handle, int &fd, FusedHostCpuKernelFunctions &kernel_funcs); | ||
| 55 | ge::graphStatus CheckOrCreateHandle(const std::string &op_name, const rtStream_t stream, | 77 | ge::graphStatus CheckOrCreateHandle(const std::string &op_name, const rtStream_t stream, |
| 56 | const GertTensorData *handle_data); | 78 | const GertTensorData *handle_data); |
| 57 | AicpuResourceManager() = default; | 79 | AicpuResourceManager() = default; |
| @@ -61,6 +83,18 @@ class AicpuResourceManager { | |||
| 61 | std::function<uint32_t(void *)> run_cpu_kernel_ = nullptr; | 83 | std::function<uint32_t(void *)> run_cpu_kernel_ = nullptr; |
| 62 | std::function<AicpuHostProcFunc(std::string)> aicpu_host_find_func_ = nullptr; | 84 | std::function<AicpuHostProcFunc(std::string)> aicpu_host_find_func_ = nullptr; |
| 63 | void *so_handle_ = nullptr; | 85 | void *so_handle_ = nullptr; |
| 86 | + // CpuKernelRegister 没有注销接口。引用计数仅表示活跃模型数;引用归零后仍保留 so 映射,避免其中的 | ||
| 87 | + // std::function creator 因 dlclose 变成悬空指针,并支持后续模型复用同一产物。 | ||
| 88 | + std::mutex fused_so_mutex_; | ||
| 89 | + std::map<std::string, uint64_t> fused_register_hashes_; | ||
| 90 | + std::map<std::string, size_t> fused_register_ref_counts_; | ||
| 91 | + std::map<std::string, FusedHostCpuKernelFunctions> fused_kernel_funcs_; | ||
| 92 | + std::map<uint64_t, void *> fused_so_handles_; | ||
| 93 | + std::map<uint64_t, int> fused_so_fds_; | ||
| 94 | + std::map<uint64_t, size_t> fused_so_ref_counts_; | ||
| 95 | + std::map<uint64_t, std::vector<uint8_t>> fused_so_contents_; | ||
| 96 | + std::vector<void *> fused_quarantined_so_handles_; | ||
| 97 | + std::vector<int> fused_quarantined_so_fds_; | ||
| 64 | 98 | ||
| 65 | std::map<uint64_t, std::deque<GertTensorData>> tensors_; | 99 | std::map<uint64_t, std::deque<GertTensorData>> tensors_; |
| 66 | std::map<std::string, uint64_t> handles_; | 100 | std::map<std::string, uint64_t> handles_; |
| @@ -0,0 +1,50 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace gert { | ||
| 17 | +struct FusedHostCpuTensorMeta { | ||
| 18 | + size_t dim_num; | ||
| 19 | +}; | ||
| 20 | + | ||
| 21 | +enum FusedHostCpuBindingFlag : uint32_t { kFusedHostCpuShapeChanged = 1U, kFusedHostCpuDataChanged = 2U }; | ||
| 22 | + | ||
| 23 | +// Private C ABI payload shared by RT2 and the generated JIT SO. Keep it standard-layout; compiler, runtime and | ||
| 24 | +// generated SO must be deployed as one ABI-compatible set. | ||
| 25 | +struct FusedHostCpuTensorBinding { | ||
| 26 | + const int64_t *dims; | ||
| 27 | + uint8_t *data; | ||
| 28 | + size_t dim_num; | ||
| 29 | + size_t data_size; | ||
| 30 | + uint32_t flags; | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +struct FusedHostCpuComputeMeta { | ||
| 34 | + void *compute_state; | ||
| 35 | + size_t input_num; | ||
| 36 | + size_t output_num; | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | +struct FusedHostCpuDestroyMeta { | ||
| 40 | + void *compute_state; | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +namespace kernel { | ||
| 44 | +void *CreateFusedHostCpuComputeState(const char *register_name, void *kernel_state, | ||
| 45 | + FusedHostCpuDestroyFunc destroy_func, FusedHostCpuRunFunc run_func, | ||
| 46 | + const FusedHostCpuTensorMeta *tensor_metas, size_t io_num); | ||
| 47 | +void DestroyFusedHostCpuComputeState(void *compute_state); | ||
| 48 | +} // namespace kernel | ||
| 49 | +} // namespace gert | ||
| 50 | + | ||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | + | ||
| 29 | 30 | ||
| 30 | using namespace aicpu; | 31 | using namespace aicpu; |
| 31 | using namespace ge; | 32 | using namespace ge; |
| @@ -752,6 +753,27 @@ TEST(AicpuGraphOptimizer, InsertAicpuNodeDefAttrToOp_Deterministic) { | |||
| 752 | ASSERT_EQ(str1, str2); | 753 | ASSERT_EQ(str1, str2); |
| 753 | } | 754 | } |
| 754 | 755 | ||
| 756 | +TEST(AicpuGraphOptimizer, BuildAicpuNodeDefUsesFusedRegisterAndIoNames) { | ||
| 757 | + OpDescPtr op_desc_ptr = make_shared<OpDesc>("fused", kFusedHostCpuOpType); | ||
| 758 | + GeTensorDesc tensor_desc(GeShape({2}), FORMAT_ND, DT_INT64); | ||
| 759 | + ASSERT_EQ(op_desc_ptr->AddInputDesc("input_0", tensor_desc), GRAPH_SUCCESS); | ||
| 760 | + ASSERT_EQ(op_desc_ptr->AddOutputDesc("output_0", tensor_desc), GRAPH_SUCCESS); | ||
| 761 | + ASSERT_TRUE(AttrUtils::SetStr(op_desc_ptr, kFusedHostCpuRegisterName, "FusedHostCpu_test")); | ||
| 762 | + aicpuops::NodeDef node_def; | ||
| 763 | + ASSERT_EQ(BuildAicpuNodeDef(op_desc_ptr, node_def), SUCCESS); | ||
| 764 | + EXPECT_EQ(node_def.op(), "FusedHostCpu_test"); | ||
| 765 | + ASSERT_EQ(node_def.inputs_size(), 1); | ||
| 766 | + ASSERT_EQ(node_def.outputs_size(), 1); | ||
| 767 | + EXPECT_EQ(node_def.inputs(0).name(), "input_0"); | ||
| 768 | + EXPECT_EQ(node_def.outputs(0).name(), "output_0"); | ||
| 769 | +} | ||
| 770 | + | ||
| 771 | +TEST(AicpuGraphOptimizer, BuildAicpuNodeDefRejectsMissingFusedRegisterName) { | ||
| 772 | + OpDescPtr op_desc_ptr = make_shared<OpDesc>("fused", kFusedHostCpuOpType); | ||
| 773 | + aicpuops::NodeDef node_def; | ||
| 774 | + EXPECT_EQ(BuildAicpuNodeDef(op_desc_ptr, node_def), ge::PARAM_INVALID); | ||
| 775 | +} | ||
| 776 | + | ||
| 755 | TEST(AicpuGraphOptimizer, test_GENERATETRANSPOSE_001) { | 777 | TEST(AicpuGraphOptimizer, test_GENERATETRANSPOSE_001) { |
| 756 | map<string, GraphOptimizerPtr> graphOptimizers; | 778 | map<string, GraphOptimizerPtr> graphOptimizers; |
| 757 | GetGraphOptimizerObjs(graphOptimizers); | 779 | GetGraphOptimizerObjs(graphOptimizers); |
| @@ -113,6 +113,15 @@ TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_NoEnvFail) { | |||
| 113 | ASSERT_EQ(ret, -1); | 113 | ASSERT_EQ(ret, -1); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | +TEST_F(AicpuConstFoldingTest, IsCpuConstantFoldingFusedOpSupported) { | ||
| 117 | + SetEnvSafe("ASCEND_HOME_PATH", "/tmp", 1); | ||
| 118 | + ASSERT_EQ(InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); }), 0); | ||
| 119 | + EXPECT_EQ(IsCpuConstantFoldingFusedOpSupported(nullptr), 0); | ||
| 120 | + EXPECT_EQ(IsCpuConstantFoldingFusedOpSupported(""), 0); | ||
| 121 | + EXPECT_EQ(IsCpuConstantFoldingFusedOpSupported("unsupported"), 0); | ||
| 122 | + EXPECT_EQ(IsCpuConstantFoldingFusedOpSupported("testop"), 1); | ||
| 123 | +} | ||
| 124 | + | ||
| 116 | TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_LoadSoTraversal) { | 125 | TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_LoadSoTraversal) { |
| 117 | std::string tmp_dir = "/tmp/test_folding_ut_" + std::to_string(getpid()); | 126 | std::string tmp_dir = "/tmp/test_folding_ut_" + std::to_string(getpid()); |
| 118 | std::string host_cpu_dir = tmp_dir + "/opp/built-in/op_impl/host_cpu/"; | 127 | std::string host_cpu_dir = tmp_dir + "/opp/built-in/op_impl/host_cpu/"; |
| @@ -18,7 +18,9 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | + | ||
| 21 | 22 | ||
| 23 | + | ||
| 22 | 24 | ||
| 23 | using namespace aicpu; | 25 | using namespace aicpu; |
| 24 | using namespace ge; | 26 | using namespace ge; |
| @@ -148,6 +150,41 @@ TEST(HostCpuOpsKernelBuilder, GenerateTask_SUCCESS) { | |||
| 148 | printf("end===================\n"); | 150 | printf("end===================\n"); |
| 149 | } | 151 | } |
| 150 | 152 | ||
| 153 | +TEST(HostCpuOpsKernelBuilder, CalcOpRunningParamBuildsFusedNodeDef) { | ||
| 154 | + HostCpuOpsKernelBuilder hostCpuKernelBuilder; | ||
| 155 | + map<string, string> options; | ||
| 156 | + options[SOC_VERSION] = "Ascend910"; | ||
| 157 | + ASSERT_EQ(hostCpuKernelBuilder.Initialize(options), SUCCESS); | ||
| 158 | + | ||
| 159 | + auto graph = make_shared<ComputeGraph>("fused_host_cpu_graph"); | ||
| 160 | + auto op_desc = make_shared<OpDesc>("fused", kFusedHostCpuOpType); | ||
| 161 | + GeTensorDesc tensor_desc(GeShape({2}), FORMAT_ND, DT_INT64); | ||
| 162 | + ASSERT_EQ(op_desc->AddInputDesc("input_0", tensor_desc), GRAPH_SUCCESS); | ||
| 163 | + ASSERT_EQ(op_desc->AddOutputDesc("output_0", tensor_desc), GRAPH_SUCCESS); | ||
| 164 | + ASSERT_TRUE(AttrUtils::SetStr(op_desc, kFusedHostCpuRegisterName, "FusedHostCpu_builder_test")); | ||
| 165 | + ASSERT_TRUE(AttrUtils::SetStr(op_desc, "opKernelLib", "HOSTCPUKernel")); | ||
| 166 | + ASSERT_TRUE(AttrUtils::SetInt(op_desc, ge::ATTR_NAME_UNKNOWN_SHAPE_TYPE, DEPEND_IN_SHAPE)); | ||
| 167 | + auto node = graph->AddNode(op_desc); | ||
| 168 | + ASSERT_NE(node, nullptr); | ||
| 169 | + | ||
| 170 | + ASSERT_EQ(hostCpuKernelBuilder.CalcOpRunningParam(*node), SUCCESS); | ||
| 171 | + Buffer node_def_buffer; | ||
| 172 | + ASSERT_TRUE(AttrUtils::GetZeroCopyBytes(op_desc, kCustomizedOpDef, node_def_buffer)); | ||
| 173 | + aicpuops::NodeDef node_def; | ||
| 174 | + ASSERT_TRUE(node_def.ParseFromArray(node_def_buffer.GetData(), static_cast<int32_t>(node_def_buffer.GetSize()))); | ||
| 175 | + EXPECT_EQ(node_def.op(), "FusedHostCpu_builder_test"); | ||
| 176 | + ASSERT_EQ(node_def.inputs_size(), 1); | ||
| 177 | + ASSERT_EQ(node_def.outputs_size(), 1); | ||
| 178 | + EXPECT_EQ(node_def.inputs(0).name(), "input_0"); | ||
| 179 | + EXPECT_EQ(node_def.outputs(0).name(), "output_0"); | ||
| 180 | + | ||
| 181 | + RunContext context = CreateContext(); | ||
| 182 | + vector<domi::TaskDef> tasks; | ||
| 183 | + ASSERT_EQ(hostCpuKernelBuilder.GenerateTask(*node, context, tasks), SUCCESS); | ||
| 184 | + ASSERT_EQ(tasks.size(), 1U); | ||
| 185 | + EXPECT_EQ(tasks[0].kernel().context().kernel_type(), 8U); | ||
| 186 | + DestroyContext(context); | ||
| 187 | +} | ||
| 151 | TEST(HostCpuOpsKernelBuilder, CalcOpRunningParam_Original_Unknown_FAIL) { | 188 | TEST(HostCpuOpsKernelBuilder, CalcOpRunningParam_Original_Unknown_FAIL) { |
| 152 | HostCpuOpsKernelBuilder hostCpuKernelBuilder; | 189 | HostCpuOpsKernelBuilder hostCpuKernelBuilder; |
| 153 | map<string, string> options; | 190 | map<string, string> options; |
| @@ -62,6 +62,7 @@ target_include_directories(autofuse_test PRIVATE | |||
| 62 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/graph_metadef | 62 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/graph_metadef |
| 63 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/graph_metadef/graph | 63 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/graph_metadef/graph |
| 64 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/ascir | 64 | ${ASCEND_INSTALL_PATH}/pkg_inc/autofuse/ascir |
| 65 | + ${ASCEND_INSTALL_PATH}/pkg_inc | ||
| 65 | ) | 66 | ) |
| 66 | 67 | ||
| 67 | target_link_libraries(autofuse_test PRIVATE | 68 | target_link_libraries(autofuse_test PRIVATE |
| @@ -8,287 +8,754 @@ | |||
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | - | ||
| 12 | - | ||
| 13 | 11 | ||
| 12 | + | ||
| 13 | + | ||
| 14 | 14 | ||
| 15 | + | ||
| 15 | 16 | ||
| 16 | 17 | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 17 | 22 | ||
| 18 | -#include "graph/op_so_bin.h" | 23 | +#include "graph/ge_local_context.h" |
| 19 | 24 | ||
| 20 | 25 | ||
| 21 | 26 | ||
| 22 | 27 | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +// The open-source ST links a placeholder constant-folding library, so provide the CpuKernel registration symbols | ||
| 32 | +// that the generated JIT so normally resolves from the real libconstant_folding_ops.so on a product installation. | ||
| 33 | +namespace aicpu { | ||
| 34 | +namespace { | ||
| 35 | +std::map<std::string, KERNEL_CREATOR_FUN> &GetTestCpuKernelCreators() { | ||
| 36 | + static std::map<std::string, KERNEL_CREATOR_FUN> creators; | ||
| 37 | + return creators; | ||
| 38 | +} | ||
| 39 | +} // namespace | ||
| 40 | + | ||
| 41 | +bool RegistCpuKernel(const std::string &type, const KERNEL_CREATOR_FUN &fun) { | ||
| 42 | + return GetTestCpuKernelCreators().emplace(type, fun).second; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +CpuKernelRegister &CpuKernelRegister::Instance() { | ||
| 46 | + static CpuKernelRegister instance; | ||
| 47 | + return instance; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +std::shared_ptr<CpuKernel> CpuKernelRegister::GetCpuKernel(const std::string &op_type) { | ||
| 51 | + const auto iter = GetTestCpuKernelCreators().find(op_type); | ||
| 52 | + return (iter == GetTestCpuKernelCreators().cend()) ? nullptr : iter->second(); | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +std::string CpuKernelContext::GetOpType() const { | ||
| 56 | + return {}; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +Tensor *CpuKernelContext::Input(const uint32_t) const { | ||
| 60 | + return nullptr; | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +Tensor *CpuKernelContext::Output(const uint32_t) const { | ||
| 64 | + return nullptr; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +uint32_t CpuKernelContext::GetInputsSize() const { | ||
| 68 | + return 0U; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +uint32_t CpuKernelContext::GetOutputsSize() const { | ||
| 72 | + return 0U; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +std::shared_ptr<TensorShape> Tensor::GetTensorShape() const { | ||
| 76 | + return nullptr; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +DataType Tensor::GetDataType() const { | ||
| 80 | + return DT_UNDEFINED; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +void *Tensor::GetData() const { | ||
| 84 | + return nullptr; | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +uint64_t Tensor::GetDataSize() const { | ||
| 88 | + return 0U; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +Format TensorShape::GetFormat() const { | ||
| 92 | + return FORMAT_ND; | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +std::vector<int64_t> TensorShape::GetDimSizes() const { | ||
| 96 | + return {}; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +int64_t TensorShape::GetDimSize(int32_t) const { | ||
| 100 | + return 0; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +int32_t TensorShape::GetDims() const { | ||
| 104 | + return 0; | ||
| 105 | +} | ||
| 106 | +} // namespace aicpu | ||
| 107 | + | ||
| 108 | +// The loader test does not load the product constant-folding library. Export the private chain-plan symbols so the | ||
| 109 | +// generated JIT so can resolve them when validating registration; this test does not execute the plan. | ||
| 110 | +size_t g_create_fused_chain_plan_count = 0U; | ||
| 111 | + | ||
| 112 | +extern "C" __attribute__((visibility("default"))) void *CreateCpuConstantFoldingFusedChainPlan(const void *, size_t, | ||
| 113 | + size_t, size_t) { | ||
| 114 | + ++g_create_fused_chain_plan_count; | ||
| 115 | + return reinterpret_cast<void *>(1U); | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +extern "C" __attribute__((visibility("default"))) int32_t RunCpuConstantFoldingFusedChainPlan(void *, uint32_t) { | ||
| 119 | + return 0; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +extern "C" __attribute__((visibility("default"))) int32_t RunCpuConstantFoldingFusedChainPlanBindings(void *, | ||
| 123 | + const void *, | ||
| 124 | + uint32_t) { | ||
| 125 | + return 0; | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +extern "C" __attribute__((visibility("default"))) void DestroyCpuConstantFoldingFusedChainPlan(void *) {} | ||
| 23 | 129 | ||
| 24 | namespace ge { | 130 | namespace ge { |
| 25 | namespace { | 131 | namespace { |
| 132 | + | ||
| 133 | +constexpr char kHostFusionStA[] = "HostFusionStA"; | ||
| 134 | +constexpr char kHostFusionStB[] = "HostFusionStB"; | ||
| 135 | +constexpr char kHostFusionStMissing[] = "HostFusionStMissing"; | ||
| 136 | +constexpr char kHostFusionStAfterMissing[] = "HostFusionStAfterMissing"; | ||
| 137 | +constexpr char kHostCpuEngineName[] = "DNN_VM_HOST_CPU"; | ||
| 138 | +constexpr char kHostCpuKernelLibName[] = "DNN_VM_HOST_CPU_OP_STORE"; | ||
| 26 | 139 | ||
| 27 | -std::string GetToolkitHome() { | 140 | +class ScopedEnvVar { |
| 28 | - const char *home = std::getenv("ASCEND_HOME_PATH"); | ||
| 29 | - if ((home != nullptr) && (home[0] != '\0')) { | ||
| 30 | - return home; | ||
| 31 | - } | ||
| 32 | - const char *install_path = std::getenv("ASCEND_INSTALL_PATH"); | ||
| 33 | - if ((install_path != nullptr) && (install_path[0] != '\0')) { | ||
| 34 | - return install_path; | ||
| 35 | - } | ||
| 36 | - return "/usr/local/Ascend/cann-9.2.0/x86_64-linux"; | ||
| 37 | -} | ||
| 38 | - | ||
| 39 | -std::string GetToolkitOpp(const std::string &home) { | ||
| 40 | - constexpr char kX86Suffix[] = "/x86_64-linux"; | ||
| 41 | - if (home.size() > (sizeof(kX86Suffix) - 1U) && | ||
| 42 | - home.compare(home.size() - (sizeof(kX86Suffix) - 1U), sizeof(kX86Suffix) - 1U, kX86Suffix) == 0) { | ||
| 43 | - return home.substr(0U, home.size() - (sizeof(kX86Suffix) - 1U)) + "/opp"; | ||
| 44 | - } | ||
| 45 | - return home + "/opp"; | ||
| 46 | -} | ||
| 47 | - | ||
| 48 | -NodePtr MakeNode(const ComputeGraphPtr &graph, const std::string &name, const std::string &type, const size_t inputs, | ||
| 49 | - const size_t outputs) { | ||
| 50 | - const GeTensorDesc desc(GeShape({2, 3}), FORMAT_ND, DT_INT64); | ||
| 51 | - auto op_desc = std::make_shared<OpDesc>(name, type); | ||
| 52 | - for (size_t i = 0U; i < inputs; ++i) { | ||
| 53 | - EXPECT_EQ(op_desc->AddInputDesc("input" + std::to_string(i), desc), GRAPH_SUCCESS); | ||
| 54 | - } | ||
| 55 | - for (size_t i = 0U; i < outputs; ++i) { | ||
| 56 | - EXPECT_EQ(op_desc->AddOutputDesc("output" + std::to_string(i), desc), GRAPH_SUCCESS); | ||
| 57 | - } | ||
| 58 | - return graph->AddNode(op_desc); | ||
| 59 | -} | ||
| 60 | - | ||
| 61 | -void Connect(const NodePtr &source, const size_t source_index, const NodePtr &target, const size_t target_index) { | ||
| 62 | - ASSERT_EQ(GraphUtils::AddEdge(source->GetOutDataAnchor(static_cast<int32_t>(source_index)), | ||
| 63 | - target->GetInDataAnchor(static_cast<int32_t>(target_index))), | ||
| 64 | - GRAPH_SUCCESS); | ||
| 65 | -} | ||
| 66 | - | ||
| 67 | -HostCpuFusionRegion MakeRegion(const ComputeGraphPtr &graph) { | ||
| 68 | - const auto data = MakeNode(graph, "data", "Data", 0U, 1U); | ||
| 69 | - const auto first = MakeNode(graph, "first", "HostST", 1U, 2U); | ||
| 70 | - const auto second = MakeNode(graph, "second", "HostST", 1U, 1U); | ||
| 71 | - const auto side = MakeNode(graph, "side", "DeviceOp", 1U, 1U); | ||
| 72 | - const auto output = MakeNode(graph, "output", "NetOutput", 2U, 0U); | ||
| 73 | - Connect(data, 0U, first, 0U); | ||
| 74 | - Connect(first, 0U, second, 0U); | ||
| 75 | - Connect(first, 1U, side, 0U); | ||
| 76 | - Connect(second, 0U, output, 0U); | ||
| 77 | - Connect(side, 0U, output, 1U); | ||
| 78 | - | ||
| 79 | - HostCpuFusionRegion region; | ||
| 80 | - region.chain_id = "st_codegen_chain"; | ||
| 81 | - region.nodes = {first, second}; | ||
| 82 | - region.external_inputs = {data->GetOutDataAnchor(0)}; | ||
| 83 | - region.external_outputs = {{first->GetOutDataAnchor(1), {side->GetInDataAnchor(0)}}, | ||
| 84 | - {second->GetOutDataAnchor(0), {output->GetInDataAnchor(0)}}}; | ||
| 85 | - return region; | ||
| 86 | -} | ||
| 87 | - | ||
| 88 | -void MarkHostCpuCandidateForPassSt(const NodePtr &node) { | ||
| 89 | - node->GetOpDesc()->SetOpEngineName("DNN_VM_HOST_CPU"); | ||
| 90 | - node->GetOpDesc()->SetOpKernelLibName("DNN_VM_HOST_CPU_OP_STORE"); | ||
| 91 | - ASSERT_TRUE(AttrUtils::SetBool(node->GetOpDesc(), "SmallShapeHostcpu", true)); | ||
| 92 | -} | ||
| 93 | - | ||
| 94 | -ComputeGraphPtr BuildPassGraph() { | ||
| 95 | - auto graph = std::make_shared<ComputeGraph>("host_cpu_fusion_pass_st"); | ||
| 96 | - const auto data = MakeNode(graph, "pass_data", "Data", 0U, 1U); | ||
| 97 | - const auto first = MakeNode(graph, "pass_first", "HostPassA", 1U, 1U); | ||
| 98 | - const auto second = MakeNode(graph, "pass_second", "HostPassB", 1U, 1U); | ||
| 99 | - const auto output = MakeNode(graph, "pass_output", "NetOutput", 1U, 0U); | ||
| 100 | - Connect(data, 0U, first, 0U); | ||
| 101 | - Connect(first, 0U, second, 0U); | ||
| 102 | - Connect(second, 0U, output, 0U); | ||
| 103 | - MarkHostCpuCandidateForPassSt(first); | ||
| 104 | - MarkHostCpuCandidateForPassSt(second); | ||
| 105 | - return graph; | ||
| 106 | -} | ||
| 107 | - | ||
| 108 | -class MinimalCustomOpCompilerForPassSt final : public HostCpuFusionCompiler { | ||
| 109 | public: | 141 | public: |
| 110 | - Status Compile(const std::string &, std::vector<uint8_t> &so_data) const override { | 142 | + ScopedEnvVar(std::string name, const std::string &value) : name_(std::move(name)) { |
| 111 | - return HostCpuFusionCompiler::Compile( | 143 | + const char *old_value = std::getenv(name_.c_str()); |
| 112 | - "extern \"C\" __attribute__((visibility(\"default\"))) unsigned int " | 144 | + if (old_value != nullptr) { |
| 113 | - "GetRegisteredCustomOpCreatorAbiVersion() { return 2U; }\n" | 145 | + had_old_value_ = true; |
| 114 | - "extern \"C\" __attribute__((visibility(\"default\"))) unsigned long " | 146 | + old_value_ = old_value; |
| 115 | - "GetRegisteredCustomOpCreatorNum() { return 0U; }\n" | ||
| 116 | - "extern \"C\" __attribute__((visibility(\"default\"))) int " | ||
| 117 | - "GetRegisteredCustomOpCreators(void *, unsigned long, unsigned long) { return 0; }\n", | ||
| 118 | - so_data); | ||
| 119 | - } | ||
| 120 | -}; | ||
| 121 | - | ||
| 122 | -bool SupportAllForPassSt(const std::string &) { | ||
| 123 | - return true; | ||
| 124 | -} | ||
| 125 | - | ||
| 126 | -class EnvGuard final { | ||
| 127 | - public: | ||
| 128 | - EnvGuard(const char *name, const char *value) : name_(name), old_(), had_old_(false) { | ||
| 129 | - const char *old = std::getenv(name); | ||
| 130 | - if (old != nullptr) { | ||
| 131 | - old_ = old; | ||
| 132 | - had_old_ = true; | ||
| 133 | } | 147 | } |
| 134 | - EXPECT_EQ(setenv(name, value, 1), 0); | 148 | + valid_ = (setenv(name_.c_str(), value.c_str(), 1) == 0); |
| 135 | } | 149 | } |
| 136 | - ~EnvGuard() { | 150 | + |
| 137 | - if (had_old_) { | 151 | + ~ScopedEnvVar() { |
| 138 | - (void)setenv(name_.c_str(), old_.c_str(), 1); | 152 | + if (had_old_value_) { |
| 153 | + (void)setenv(name_.c_str(), old_value_.c_str(), 1); | ||
| 139 | } else { | 154 | } else { |
| 140 | (void)unsetenv(name_.c_str()); | 155 | (void)unsetenv(name_.c_str()); |
| 141 | } | 156 | } |
| 142 | } | 157 | } |
| 143 | 158 | ||
| 159 | + bool IsValid() const { | ||
| 160 | + return valid_; | ||
| 161 | + } | ||
| 162 | + | ||
| 144 | private: | 163 | private: |
| 145 | std::string name_; | 164 | std::string name_; |
| 146 | - std::string old_; | 165 | + std::string old_value_; |
| 147 | - bool had_old_; | 166 | + bool had_old_value_ = false; |
| 167 | + bool valid_ = false; | ||
| 148 | }; | 168 | }; |
| 149 | 169 | ||
| 170 | +class StFakeCompiler final : public HostCpuFusionCompiler { | ||
| 171 | + public: | ||
| 172 | + Status Compile(const std::string &, std::vector<uint8_t> &so_data) const override { | ||
| 173 | + so_data.assign(20U, 0U); | ||
| 174 | + so_data[0] = 0x7FU; | ||
| 175 | + so_data[1] = 'E'; | ||
| 176 | + so_data[2] = 'L'; | ||
| 177 | + so_data[3] = 'F'; | ||
| 178 | + so_data[4] = 2U; | ||
| 179 | + so_data[5] = 1U; | ||
| 180 | + so_data[6] = 1U; | ||
| 181 | + so_data[16] = 3U; | ||
| 182 | + return SUCCESS; | ||
| 183 | + } | ||
| 184 | +}; | ||
| 185 | + | ||
| 186 | +NodePtr AddNode(const ComputeGraphPtr &graph, const std::string &name, const std::string &type, | ||
| 187 | + const size_t input_count, const size_t output_count) { | ||
| 188 | + const GeTensorDesc desc(GeShape({2}), FORMAT_ND, DT_INT64); | ||
| 189 | + auto op_desc = std::make_shared<OpDesc>(name, type); | ||
| 190 | + for (size_t i = 0U; i < input_count; ++i) { | ||
| 191 | + if (op_desc->AddInputDesc("x", desc) != GRAPH_SUCCESS) { | ||
| 192 | + return nullptr; | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + for (size_t i = 0U; i < output_count; ++i) { | ||
| 196 | + if (op_desc->AddOutputDesc("y", desc) != GRAPH_SUCCESS) { | ||
| 197 | + return nullptr; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + return graph->AddNode(op_desc); | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +void MarkFusionCandidate(const NodePtr &node) { | ||
| 204 | + node->GetOpDesc()->SetOpEngineName(kHostCpuEngineName); | ||
| 205 | + node->GetOpDesc()->SetOpKernelLibName(kHostCpuKernelLibName); | ||
| 206 | + ASSERT_TRUE(AttrUtils::SetBool(node->GetOpDesc(), "SmallShapeHostcpu", true)); | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +ComputeGraphPtr BuildCoverageChainGraph() { | ||
| 210 | + auto graph = std::make_shared<ComputeGraph>("host_cpu_coverage_chain"); | ||
| 211 | + auto data = AddNode(graph, "data", "Data", 0U, 1U); | ||
| 212 | + auto first = AddNode(graph, "first", kHostFusionStA, 1U, 1U); | ||
| 213 | + auto second = AddNode(graph, "second", kHostFusionStB, 1U, 1U); | ||
| 214 | + auto output = AddNode(graph, "output", "NetOutput", 1U, 0U); | ||
| 215 | + if ((data == nullptr) || (first == nullptr) || (second == nullptr) || (output == nullptr)) { | ||
| 216 | + return nullptr; | ||
| 217 | + } | ||
| 218 | + if ((GraphUtils::AddEdge(data->GetOutDataAnchor(0), first->GetInDataAnchor(0)) != GRAPH_SUCCESS) || | ||
| 219 | + (GraphUtils::AddEdge(first->GetOutDataAnchor(0), second->GetInDataAnchor(0)) != GRAPH_SUCCESS) || | ||
| 220 | + (GraphUtils::AddEdge(second->GetOutDataAnchor(0), output->GetInDataAnchor(0)) != GRAPH_SUCCESS)) { | ||
| 221 | + return nullptr; | ||
| 222 | + } | ||
| 223 | + MarkFusionCandidate(first); | ||
| 224 | + MarkFusionCandidate(second); | ||
| 225 | + return graph; | ||
| 226 | +} | ||
| 227 | + | ||
| 228 | +HostCpuFusionRegion BuildCoverageRegion(const ComputeGraphPtr &graph) { | ||
| 229 | + HostCpuFusionRegion region; | ||
| 230 | + region.chain_id = "st_coverage_region"; | ||
| 231 | + const auto data = graph->FindNode("data"); | ||
| 232 | + const auto first = graph->FindNode("first"); | ||
| 233 | + const auto second = graph->FindNode("second"); | ||
| 234 | + const auto output = graph->FindNode("output"); | ||
| 235 | + region.nodes = {first, second}; | ||
| 236 | + region.external_inputs = {data->GetOutDataAnchor(0)}; | ||
| 237 | + region.external_outputs = {{second->GetOutDataAnchor(0), {output->GetInDataAnchor(0)}}}; | ||
| 238 | + return region; | ||
| 239 | +} | ||
| 240 | + | ||
| 150 | } // namespace | 241 | } // namespace |
| 151 | 242 | ||
| 152 | -// 用例描述:验证 HostCPU 融合区域能够生成当前 CustomOp 编排源码并编译为 ELF SO。 | 243 | +// 用例描述:验证 HostCPU 编排源码可真实编译,并注册到共享 CpuKernelRegister。 |
| 153 | -// 预置条件:使用本机 Toolkit 头文件和 g++,构造带内部中间张量及两个外部输出的融合区域。 | 244 | +// 预置条件:Linux 环境已安装可用 Toolkit 头文件和目标架构 g++,测试提供 CpuKernelRegister 符号。 |
| 154 | -// 测试步骤:生成源码,检查输入/输出绑定与 CustomOp ABI,再执行 JIT 编译。 | 245 | +// 测试步骤:生成两节点融合源码并编译,同一 so 加载两次,创建状态后首次绑定执行,再释放引用并复用。 |
| 155 | -// 预期结果:源码生成成功;工具包提供 HostCPU ABI 时编译产物为有效 ELF 共享对象,否则返回 UNSUPPORTED。 | 246 | +// 预期结果:模型加载期不创建整链 plan,首次执行才创建一次;引用归零后 so 仍可重新加载。 |
| 156 | -TEST(HostCpuFusionCodegenST, GeneratesAndCompilesCurrentCustomOp) { | 247 | +TEST(HostCpuFusionCodegenST, CompilesLoadsAndKeepsCpuKernelRegistered) { |
| 157 | -#if defined(__linux__) | 248 | +#if !defined(__linux__) |
| 158 | - const auto toolkit_home = GetToolkitHome(); | ||
| 159 | - EnvGuard home("ASCEND_HOME_PATH", toolkit_home.c_str()); | ||
| 160 | - EnvGuard opp("ASCEND_OPP_PATH", ""); | ||
| 161 | - auto graph = std::make_shared<ComputeGraph>("host_cpu_codegen_st"); | ||
| 162 | - const auto region = MakeRegion(graph); | ||
| 163 | - HostCpuFusionCodegenResult result; | ||
| 164 | - ASSERT_EQ(HostCpuFusionCodegen().Generate(region, result), SUCCESS); | ||
| 165 | - EXPECT_EQ(result.register_name, "FusedHostCpu_st_codegen_chain"); | ||
| 166 | - EXPECT_NE(result.source.find("internal_tensor_0"), std::string::npos); | ||
| 167 | - EXPECT_NE(result.source.find("std::array<const gert::Tensor *, 1U>"), std::string::npos); | ||
| 168 | - EXPECT_NE(result.source.find("std::array<gert::Tensor *, 2U>"), std::string::npos); | ||
| 169 | - EXPECT_NE(result.source.find("REG_OP_BACKEND"), std::string::npos); | ||
| 170 | - EXPECT_NE(result.source.find("GetRegisteredCustomOpCreatorAbiVersion"), std::string::npos); | ||
| 171 | - | ||
| 172 | - std::vector<uint8_t> so_data; | ||
| 173 | - const auto compile_status = HostCpuFusionCompiler().Compile(result.source, so_data); | ||
| 174 | - if (compile_status == SUCCESS) { | ||
| 175 | - ASSERT_GT(so_data.size(), 20U); | ||
| 176 | - EXPECT_EQ(so_data[0], 0x7FU); | ||
| 177 | - EXPECT_EQ(so_data[1], 'E'); | ||
| 178 | - EXPECT_EQ(so_data[2], 'L'); | ||
| 179 | - EXPECT_EQ(so_data[3], 'F'); | ||
| 180 | - } else { | ||
| 181 | - // Older Toolkit packages may not expose the HostCpuExecuteOp ABI yet. | ||
| 182 | - EXPECT_EQ(compile_status, UNSUPPORTED); | ||
| 183 | - EXPECT_TRUE(so_data.empty()); | ||
| 184 | - } | ||
| 185 | - | ||
| 186 | GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | 249 | GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; |
| 250 | + | ||
| 251 | + const std::string opp_path = EnvPath().GetAscendInstallPath() + "/opp"; | ||
| 252 | + const ScopedEnvVar opp_env("ASCEND_OPP_PATH", opp_path); | ||
| 253 | + const ScopedEnvVar home_env("ASCEND_HOME_PATH", EnvPath().GetAirBasePath()); | ||
| 254 | + ASSERT_TRUE(opp_env.IsValid()); | ||
| 255 | + ASSERT_TRUE(home_env.IsValid()); | ||
| 256 | + | ||
| 257 | + auto graph = std::make_shared<ComputeGraph>("host_cpu_fusion_st"); | ||
| 258 | + auto data = AddNode(graph, "data", "Data", 0U, 1U); | ||
| 259 | + auto first = AddNode(graph, "first", kHostFusionStA, 1U, 1U); | ||
| 260 | + auto second = AddNode(graph, "second", kHostFusionStB, 1U, 1U); | ||
| 261 | + auto output = AddNode(graph, "output", "NetOutput", 1U, 0U); | ||
| 262 | + ASSERT_NE(data, nullptr); | ||
| 263 | + ASSERT_NE(first, nullptr); | ||
| 264 | + ASSERT_NE(second, nullptr); | ||
| 265 | + ASSERT_NE(output, nullptr); | ||
| 266 | + ASSERT_EQ(GraphUtils::AddEdge(data->GetOutDataAnchor(0), first->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 267 | + ASSERT_EQ(GraphUtils::AddEdge(first->GetOutDataAnchor(0), second->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 268 | + ASSERT_EQ(GraphUtils::AddEdge(second->GetOutDataAnchor(0), output->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 269 | + | ||
| 270 | + HostCpuFusionRegion region; | ||
| 271 | + region.chain_id = "st_actual_compile"; | ||
| 272 | + region.nodes = {first, second}; | ||
| 273 | + region.external_inputs = {data->GetOutDataAnchor(0)}; | ||
| 274 | + region.external_outputs = {{second->GetOutDataAnchor(0), {output->GetInDataAnchor(0)}}}; | ||
| 275 | + HostCpuFusionCodegenResult result; | ||
| 276 | + HostCpuFusionCodegen codegen; | ||
| 277 | + ASSERT_EQ(codegen.Generate(region, result), SUCCESS); | ||
| 278 | + HostCpuFusionCompiler compiler; | ||
| 279 | + ASSERT_EQ(compiler.Compile(result.source, result.so_data), SUCCESS); | ||
| 280 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo(result.register_name, result.so_data.data(), | ||
| 281 | + result.so_data.size()), | ||
| 282 | + GRAPH_SUCCESS); | ||
| 283 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo(result.register_name, result.so_data.data(), | ||
| 284 | + result.so_data.size()), | ||
| 285 | + GRAPH_SUCCESS); | ||
| 286 | + | ||
| 287 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(result.register_name), nullptr); | ||
| 288 | + const auto kernel_funcs = | ||
| 289 | + gert::AicpuResourceManager::GetInstance().GetFusedHostCpuKernelFunctions(result.register_name); | ||
| 290 | + ASSERT_NE(kernel_funcs.create_func, nullptr); | ||
| 291 | + ASSERT_NE(kernel_funcs.destroy_func, nullptr); | ||
| 292 | + ASSERT_NE(kernel_funcs.run_func, nullptr); | ||
| 293 | + g_create_fused_chain_plan_count = 0U; | ||
| 294 | + void *kernel_state = kernel_funcs.create_func(); | ||
| 295 | + ASSERT_NE(kernel_state, nullptr); | ||
| 296 | + EXPECT_EQ(g_create_fused_chain_plan_count, 0U); | ||
| 297 | + int64_t dims[] = {2}; | ||
| 298 | + int64_t input_data[] = {1, 2}; | ||
| 299 | + int64_t output_data[] = {0, 0}; | ||
| 300 | + gert::FusedHostCpuTensorBinding bindings[] = { | ||
| 301 | + {dims, reinterpret_cast<uint8_t *>(input_data), 1U, sizeof(input_data), | ||
| 302 | + gert::kFusedHostCpuShapeChanged | gert::kFusedHostCpuDataChanged}, | ||
| 303 | + {dims, reinterpret_cast<uint8_t *>(output_data), 1U, sizeof(output_data), | ||
| 304 | + gert::kFusedHostCpuShapeChanged | gert::kFusedHostCpuDataChanged}}; | ||
| 305 | + EXPECT_EQ( | ||
| 306 | + kernel_funcs.run_func(kernel_state, bindings, gert::kFusedHostCpuShapeChanged | gert::kFusedHostCpuDataChanged), | ||
| 307 | + 0U); | ||
| 308 | + EXPECT_EQ(g_create_fused_chain_plan_count, 1U); | ||
| 309 | + // 绑定未变化时应复用已创建的 plan,不重复构建内部执行计划。 | ||
| 310 | + EXPECT_EQ(kernel_funcs.run_func(kernel_state, bindings, 0U), 0U); | ||
| 311 | + EXPECT_EQ(g_create_fused_chain_plan_count, 1U); | ||
| 312 | + kernel_funcs.destroy_func(kernel_state); | ||
| 313 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(result.register_name), GRAPH_SUCCESS); | ||
| 314 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(result.register_name), nullptr); | ||
| 315 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(result.register_name), GRAPH_SUCCESS); | ||
| 316 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(result.register_name), nullptr); | ||
| 317 | + EXPECT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(result.register_name), ge::PARAM_INVALID); | ||
| 318 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo(result.register_name, result.so_data.data(), | ||
| 319 | + result.so_data.size()), | ||
| 320 | + GRAPH_SUCCESS); | ||
| 321 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(result.register_name), GRAPH_SUCCESS); | ||
| 187 | 322 | ||
| 188 | } | 323 | } |
| 189 | 324 | ||
| 190 | -TEST(HostCpuFusionCodegenST, ExercisesCodegenRejectionAndNameBoundaries) { | 325 | +// 用例描述:验证同一进程连续加载两个不同的 HostCPU 融合 SO。 |
| 191 | - auto graph = std::make_shared<ComputeGraph>("host_cpu_codegen_rejection"); | 326 | +// 预置条件:Linux 环境已安装可用 Toolkit 头文件和目标架构 g++,测试提供 CpuKernelRegister 符号。 |
| 192 | - const auto valid = MakeRegion(graph); | 327 | +// 测试步骤:为同一融合区域生成两个不同注册名的 SO,依次加载并查询各自的 private C ABI。 |
| 328 | +// 预期结果:两个 SO 均独立完成静态注册,且分别返回有效的 private C ABI。 | ||
| 329 | +TEST(HostCpuFusionCodegenST, LoadsDifferentFusedSharedObjectsIndependently) { | ||
| 330 | + | ||
| 331 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 332 | + | ||
| 333 | + const std::string opp_path = EnvPath().GetAscendInstallPath() + "/opp"; | ||
| 334 | + const ScopedEnvVar opp_env("ASCEND_OPP_PATH", opp_path); | ||
| 335 | + const ScopedEnvVar home_env("ASCEND_HOME_PATH", EnvPath().GetAirBasePath()); | ||
| 336 | + ASSERT_TRUE(opp_env.IsValid()); | ||
| 337 | + ASSERT_TRUE(home_env.IsValid()); | ||
| 338 | + | ||
| 339 | + auto graph = std::make_shared<ComputeGraph>("host_cpu_fusion_multi_so_st"); | ||
| 340 | + auto data = AddNode(graph, "data", "Data", 0U, 1U); | ||
| 341 | + auto first = AddNode(graph, "first", kHostFusionStA, 1U, 1U); | ||
| 342 | + auto second = AddNode(graph, "second", kHostFusionStB, 1U, 1U); | ||
| 343 | + auto output = AddNode(graph, "output", "NetOutput", 1U, 0U); | ||
| 344 | + ASSERT_NE(data, nullptr); | ||
| 345 | + ASSERT_NE(first, nullptr); | ||
| 346 | + ASSERT_NE(second, nullptr); | ||
| 347 | + ASSERT_NE(output, nullptr); | ||
| 348 | + ASSERT_EQ(GraphUtils::AddEdge(data->GetOutDataAnchor(0), first->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 349 | + ASSERT_EQ(GraphUtils::AddEdge(first->GetOutDataAnchor(0), second->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 350 | + ASSERT_EQ(GraphUtils::AddEdge(second->GetOutDataAnchor(0), output->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 351 | + | ||
| 352 | + HostCpuFusionRegion region; | ||
| 353 | + region.nodes = {first, second}; | ||
| 354 | + region.external_inputs = {data->GetOutDataAnchor(0)}; | ||
| 355 | + region.external_outputs = {{second->GetOutDataAnchor(0), {output->GetInDataAnchor(0)}}}; | ||
| 356 | + HostCpuFusionCodegen codegen; | ||
| 357 | + HostCpuFusionCompiler compiler; | ||
| 358 | + HostCpuFusionCodegenResult first_result; | ||
| 359 | + region.chain_id = "st_multi_so_first"; | ||
| 360 | + ASSERT_EQ(codegen.Generate(region, first_result), SUCCESS); | ||
| 361 | + ASSERT_EQ(compiler.Compile(first_result.source, first_result.so_data), SUCCESS); | ||
| 362 | + HostCpuFusionCodegenResult second_result; | ||
| 363 | + region.chain_id = "st_multi_so_second"; | ||
| 364 | + ASSERT_EQ(codegen.Generate(region, second_result), SUCCESS); | ||
| 365 | + ASSERT_EQ(compiler.Compile(second_result.source, second_result.so_data), SUCCESS); | ||
| 366 | + ASSERT_NE(first_result.so_data, second_result.so_data); | ||
| 367 | + | ||
| 368 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo( | ||
| 369 | + first_result.register_name, first_result.so_data.data(), first_result.so_data.size()), | ||
| 370 | + GRAPH_SUCCESS); | ||
| 371 | + ASSERT_EQ(gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo( | ||
| 372 | + second_result.register_name, second_result.so_data.data(), second_result.so_data.size()), | ||
| 373 | + GRAPH_SUCCESS); | ||
| 374 | + const gert::FusedHostCpuKernelFunctions first_funcs = | ||
| 375 | + gert::AicpuResourceManager::GetInstance().GetFusedHostCpuKernelFunctions(first_result.register_name); | ||
| 376 | + const gert::FusedHostCpuKernelFunctions second_funcs = | ||
| 377 | + gert::AicpuResourceManager::GetInstance().GetFusedHostCpuKernelFunctions(second_result.register_name); | ||
| 378 | + EXPECT_NE(first_funcs.create_func, nullptr); | ||
| 379 | + EXPECT_NE(first_funcs.destroy_func, nullptr); | ||
| 380 | + EXPECT_NE(first_funcs.run_func, nullptr); | ||
| 381 | + EXPECT_NE(second_funcs.create_func, nullptr); | ||
| 382 | + EXPECT_NE(second_funcs.destroy_func, nullptr); | ||
| 383 | + EXPECT_NE(second_funcs.run_func, nullptr); | ||
| 384 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(first_result.register_name), nullptr); | ||
| 385 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(second_result.register_name), nullptr); | ||
| 386 | + EXPECT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(first_result.register_name), GRAPH_SUCCESS); | ||
| 387 | + EXPECT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(second_result.register_name), | ||
| 388 | + GRAPH_SUCCESS); | ||
| 389 | + | ||
| 390 | +} | ||
| 391 | + | ||
| 392 | +// 用例描述:验证融合外层与内部原算子都不再依赖 HostCPU registry,稳态执行复用 CpuKernel plan。 | ||
| 393 | +// 预置条件:Linux 环境已安装可用 Toolkit 头文件和目标架构 g++。 | ||
| 394 | +// 测试步骤:生成三节点融合源码并编译,检查外层注册及内部 plan 创建、复用调用。 | ||
| 395 | +// 预期结果:外层使用 REGISTER_CPU_KERNEL;内部使用数组和线程级 plan,不包含 map 或 HostCpuOp API。 | ||
| 396 | +TEST(HostCpuFusionCodegenST, UsesCachedCpuKernelPlanForInternalNodes) { | ||
| 397 | + | ||
| 398 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 399 | + | ||
| 400 | + const std::string opp_path = EnvPath().GetAscendInstallPath() + "/opp"; | ||
| 401 | + const ScopedEnvVar opp_env("ASCEND_OPP_PATH", opp_path); | ||
| 402 | + const ScopedEnvVar home_env("ASCEND_HOME_PATH", EnvPath().GetAirBasePath()); | ||
| 403 | + ASSERT_TRUE(opp_env.IsValid()); | ||
| 404 | + ASSERT_TRUE(home_env.IsValid()); | ||
| 405 | + | ||
| 406 | + auto graph = std::make_shared<ComputeGraph>("host_cpu_fusion_missing_kernel_st"); | ||
| 407 | + auto data = AddNode(graph, "data", "Data", 0U, 1U); | ||
| 408 | + auto first = AddNode(graph, "first", kHostFusionStA, 1U, 1U); | ||
| 409 | + auto missing = AddNode(graph, "missing", kHostFusionStMissing, 1U, 1U); | ||
| 410 | + auto after_missing = AddNode(graph, "after_missing", kHostFusionStAfterMissing, 1U, 1U); | ||
| 411 | + auto output = AddNode(graph, "output", "NetOutput", 1U, 0U); | ||
| 412 | + ASSERT_NE(data, nullptr); | ||
| 413 | + ASSERT_NE(first, nullptr); | ||
| 414 | + ASSERT_NE(missing, nullptr); | ||
| 415 | + ASSERT_NE(after_missing, nullptr); | ||
| 416 | + ASSERT_NE(output, nullptr); | ||
| 417 | + ASSERT_EQ(GraphUtils::AddEdge(data->GetOutDataAnchor(0), first->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 418 | + ASSERT_EQ(GraphUtils::AddEdge(first->GetOutDataAnchor(0), missing->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 419 | + ASSERT_EQ(GraphUtils::AddEdge(missing->GetOutDataAnchor(0), after_missing->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 420 | + ASSERT_EQ(GraphUtils::AddEdge(after_missing->GetOutDataAnchor(0), output->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 421 | + | ||
| 422 | + HostCpuFusionRegion region; | ||
| 423 | + region.chain_id = "st_missing_kernel"; | ||
| 424 | + region.nodes = {first, missing, after_missing}; | ||
| 425 | + region.external_inputs = {data->GetOutDataAnchor(0)}; | ||
| 426 | + region.external_outputs = {{after_missing->GetOutDataAnchor(0), {output->GetInDataAnchor(0)}}}; | ||
| 427 | + HostCpuFusionCodegenResult result; | ||
| 428 | + HostCpuFusionCodegen codegen; | ||
| 429 | + ASSERT_EQ(codegen.Generate(region, result), SUCCESS); | ||
| 430 | + HostCpuFusionCompiler compiler; | ||
| 431 | + ASSERT_EQ(compiler.Compile(result.source, result.so_data), SUCCESS); | ||
| 432 | + EXPECT_NE(result.source.find("REGISTER_CPU_KERNEL(kFusedHostCpuKernel_st_missing_kernel"), std::string::npos); | ||
| 433 | + EXPECT_EQ(result.source.find("REGISTER_HOST_CPU_OP_BUILDER"), std::string::npos); | ||
| 434 | + EXPECT_EQ(result.source.find("host_cpu_kernel_registry.h"), std::string::npos); | ||
| 435 | + EXPECT_EQ(result.source.find("HostCpuOp"), std::string::npos); | ||
| 436 | + EXPECT_EQ(result.source.find("CreateHostCpuOp"), std::string::npos); | ||
| 437 | + EXPECT_EQ(result.source.find("dlsym"), std::string::npos); | ||
| 438 | + EXPECT_EQ(result.source.find("UpdateInputDesc"), std::string::npos); | ||
| 439 | + EXPECT_EQ(result.source.find("UpdateOutputDesc"), std::string::npos); | ||
| 440 | + EXPECT_EQ(result.source.find("std::map"), std::string::npos); | ||
| 441 | + EXPECT_NE(result.source.find("FusedHostCpuChainPlanGuard chain_plan_"), std::string::npos); | ||
| 442 | + EXPECT_NE(result.source.find("CreateCpuConstantFoldingFusedChainPlan("), std::string::npos); | ||
| 443 | + EXPECT_NE(result.source.find("node_descs.data(), node_descs.size(), 1U, 1U"), std::string::npos); | ||
| 444 | + EXPECT_NE(result.source.find("RunCpuConstantFoldingFusedChainPlan(chain_plan_.Get(), binding_flags)"), | ||
| 445 | + std::string::npos); | ||
| 446 | + EXPECT_NE(result.source.find("RunCpuConstantFoldingFusedChainPlanBindings("), std::string::npos); | ||
| 447 | + EXPECT_NE(result.source.find("FusedHostCpuTensorState"), std::string::npos); | ||
| 448 | + EXPECT_NE(result.source.find("FusedHostCpuTensorBinding"), std::string::npos); | ||
| 449 | + EXPECT_NE(result.source.find("ComputeBindings"), std::string::npos); | ||
| 450 | + EXPECT_NE(result.source.find("BuildFusedHostCpuRuntimeTensor"), std::string::npos); | ||
| 451 | + EXPECT_NE(result.source.find("InitializeBindings"), std::string::npos); | ||
| 452 | + EXPECT_EQ(result.source.find("BindFusedHostCpuTensor"), std::string::npos); | ||
| 453 | + EXPECT_EQ(result.source.find("if ((binding_flags == 0U) && runtime_bound_) { return Run(0U); }"), std::string::npos); | ||
| 454 | + EXPECT_EQ(result.source.find("binding_flags |= inputs["), std::string::npos); | ||
| 455 | + EXPECT_EQ(result.source.find("binding_flags |= outputs["), std::string::npos); | ||
| 456 | + EXPECT_NE(result.source.find("HasSameFusedHostCpuShape"), std::string::npos); | ||
| 457 | + EXPECT_EQ(result.source.find("GetDimSizes"), std::string::npos); | ||
| 458 | + EXPECT_NE(result.source.find("bool bindings_changed = false"), std::string::npos); | ||
| 459 | + EXPECT_NE(result.source.find("node_input_binding_indices_0{{0}}"), std::string::npos); | ||
| 460 | + EXPECT_NE(result.source.find("node_output_binding_indices_0{{-1}}"), std::string::npos); | ||
| 461 | + EXPECT_NE(result.source.find("node_input_binding_indices_1{{-1}}"), std::string::npos); | ||
| 462 | + EXPECT_NE(result.source.find("node_output_binding_indices_1{{-1}}"), std::string::npos); | ||
| 463 | + EXPECT_NE(result.source.find("node_input_binding_indices_2{{-1}}"), std::string::npos); | ||
| 464 | + EXPECT_NE(result.source.find("node_output_binding_indices_2{{1}}"), std::string::npos); | ||
| 465 | + EXPECT_EQ(result.source.find("RunCpuConstantFoldingFusedPlan"), std::string::npos); | ||
| 466 | + EXPECT_NE(result.source.find("static thread_local ge::FusedHostCpuOrchestration_st_missing_kernel orchestration"), | ||
| 467 | + std::string::npos); | ||
| 468 | + EXPECT_NE(result.source.find("void *CreateFusedHostCpuKernelState()"), std::string::npos); | ||
| 469 | + EXPECT_NE(result.source.find("if (state == nullptr) { return nullptr; }"), std::string::npos); | ||
| 470 | + EXPECT_EQ(result.source.find("state->Initialize()"), std::string::npos); | ||
| 471 | + EXPECT_NE(result.source.find("void DestroyFusedHostCpuKernelState(void *kernel_state)"), std::string::npos); | ||
| 472 | + EXPECT_NE(result.source.find("uint32_t RunFusedHostCpuKernel(void *kernel_state, const void *binding_data"), | ||
| 473 | + std::string::npos); | ||
| 474 | + EXPECT_NE(result.source.find("const bool bindings_changed"), std::string::npos); | ||
| 475 | + | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +// 用例描述:验证 HostCpuFusionPass 从候选扫描、真实 JIT 到图提交和运行时加载的完整链路。 | ||
| 479 | +// 预置条件:Linux 环境已安装可用 Toolkit 头文件和目标架构 g++,测试提供融合 SO 所需符号。 | ||
| 480 | +// 测试步骤:构造两个 HostCPU 候选节点,运行融合 Pass,从根图读取生成 SO 并交给资源管理器加载。 | ||
| 481 | +// 预期结果:原节点被一个 FusedHostCpu 替换,SO 属性完整,注册名可成功加载和释放。 | ||
| 482 | +TEST(HostCpuFusionCodegenST, PassCompilesCommitsAndLoadsFusedSharedObject) { | ||
| 483 | + | ||
| 484 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 485 | + | ||
| 486 | + const std::string opp_path = EnvPath().GetAscendInstallPath() + "/opp"; | ||
| 487 | + const ScopedEnvVar opp_env("ASCEND_OPP_PATH", opp_path); | ||
| 488 | + const ScopedEnvVar home_env("ASCEND_HOME_PATH", EnvPath().GetAirBasePath()); | ||
| 489 | + ASSERT_TRUE(opp_env.IsValid()); | ||
| 490 | + ASSERT_TRUE(home_env.IsValid()); | ||
| 491 | + | ||
| 492 | + auto graph = std::make_shared<ComputeGraph>("host_cpu_fusion_pass_st"); | ||
| 493 | + auto data = AddNode(graph, "data", "Data", 0U, 1U); | ||
| 494 | + auto first = AddNode(graph, "first", kHostFusionStA, 1U, 1U); | ||
| 495 | + auto second = AddNode(graph, "second", kHostFusionStB, 1U, 1U); | ||
| 496 | + auto output = AddNode(graph, "output", "NetOutput", 1U, 0U); | ||
| 497 | + ASSERT_NE(data, nullptr); | ||
| 498 | + ASSERT_NE(first, nullptr); | ||
| 499 | + ASSERT_NE(second, nullptr); | ||
| 500 | + ASSERT_NE(output, nullptr); | ||
| 501 | + ASSERT_EQ(GraphUtils::AddEdge(data->GetOutDataAnchor(0), first->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 502 | + ASSERT_EQ(GraphUtils::AddEdge(first->GetOutDataAnchor(0), second->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 503 | + ASSERT_EQ(GraphUtils::AddEdge(second->GetOutDataAnchor(0), output->GetInDataAnchor(0)), GRAPH_SUCCESS); | ||
| 504 | + MarkFusionCandidate(first); | ||
| 505 | + MarkFusionCandidate(second); | ||
| 506 | + | ||
| 507 | + NodeEngineMap atomic_map; | ||
| 508 | + NodeEngineMap composite_map; | ||
| 509 | + HostCpuFusionPass pass(std::make_shared<HostCpuFusionCompiler>(), [](const std::string &) { return true; }); | ||
| 510 | + ASSERT_EQ(pass.Run(graph, atomic_map, composite_map), SUCCESS); | ||
| 511 | + EXPECT_EQ(graph->FindNode("first"), nullptr); | ||
| 512 | + EXPECT_EQ(graph->FindNode("second"), nullptr); | ||
| 513 | + | ||
| 514 | + NodePtr fused_node; | ||
| 515 | + for (const auto &node : graph->GetDirectNode()) { | ||
| 516 | + if (node->GetType() == kFusedHostCpuOpType) { | ||
| 517 | + fused_node = node; | ||
| 518 | + break; | ||
| 519 | + } | ||
| 520 | + } | ||
| 521 | + ASSERT_NE(fused_node, nullptr); | ||
| 522 | + ASSERT_EQ(atomic_map.size(), 1U); | ||
| 523 | + ASSERT_EQ(composite_map.size(), 1U); | ||
| 524 | + EXPECT_EQ(output->GetInDataAnchor(0)->GetPeerOutAnchor()->GetOwnerNode(), fused_node); | ||
| 525 | + | ||
| 526 | + std::string register_name; | ||
| 527 | + std::string so_key; | ||
| 528 | + Buffer so_data; | ||
| 529 | + ASSERT_TRUE(AttrUtils::GetStr(fused_node->GetOpDesc(), kFusedHostCpuRegisterName, register_name)); | ||
| 530 | + ASSERT_TRUE(AttrUtils::GetStr(fused_node->GetOpDesc(), kFusedHostCpuSoKey, so_key)); | ||
| 531 | + ASSERT_TRUE(AttrUtils::GetBytes(graph, so_key, so_data)); | ||
| 532 | + ASSERT_GT(so_data.GetSize(), 0U); | ||
| 533 | + ASSERT_EQ( | ||
| 534 | + gert::AicpuResourceManager::GetInstance().LoadFusedHostCpuSo(register_name, so_data.GetData(), so_data.GetSize()), | ||
| 535 | + GRAPH_SUCCESS); | ||
| 536 | + EXPECT_NE(aicpu::CpuKernelRegister::Instance().GetCpuKernel(register_name), nullptr); | ||
| 537 | + EXPECT_EQ(gert::AicpuResourceManager::GetInstance().ReleaseFusedHostCpuSo(register_name), GRAPH_SUCCESS); | ||
| 538 | + | ||
| 539 | +} | ||
| 540 | + | ||
| 541 | +// 用例描述:验证 JIT 编译器对空源码和编译错误源码均安全回退。 | ||
| 542 | +// 预置条件:Linux 环境已安装可用 Toolkit 头文件和目标架构 g++。 | ||
| 543 | +// 测试步骤:依次提交空源码和语法错误源码,并检查返回码及输出缓存。 | ||
| 544 | +// 预期结果:两次调用均返回 UNSUPPORTED,且不会留下伪造的共享库数据。 | ||
| 545 | +TEST(HostCpuFusionCodegenST, CompilerRejectsEmptyAndInvalidSources) { | ||
| 546 | + | ||
| 547 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 548 | + | ||
| 549 | + const std::string opp_path = EnvPath().GetAscendInstallPath() + "/opp"; | ||
| 550 | + const ScopedEnvVar opp_env("ASCEND_OPP_PATH", opp_path); | ||
| 551 | + const ScopedEnvVar home_env("ASCEND_HOME_PATH", EnvPath().GetAirBasePath()); | ||
| 552 | + ASSERT_TRUE(opp_env.IsValid()); | ||
| 553 | + ASSERT_TRUE(home_env.IsValid()); | ||
| 554 | + | ||
| 555 | + HostCpuFusionCompiler compiler; | ||
| 556 | + std::vector<uint8_t> so_data{1U}; | ||
| 557 | + EXPECT_EQ(compiler.Compile("", so_data), UNSUPPORTED); | ||
| 558 | + EXPECT_TRUE(so_data.empty()); | ||
| 559 | + EXPECT_EQ(compiler.Compile("this is not valid C++;", so_data), UNSUPPORTED); | ||
| 560 | + EXPECT_TRUE(so_data.empty()); | ||
| 561 | + | ||
| 562 | +} | ||
| 563 | + | ||
| 564 | +// 用例描述:覆盖 JIT 工具链路径为空、缺失头文件和不同目标 CPU 的编译器选择。 | ||
| 565 | +// 预置条件:Linux 环境;不要求实际 Toolkit 头文件存在。 | ||
| 566 | +// 测试步骤:清空或设置无效 Toolkit 路径,分别设置 aarch64、x86_64 和未知目标 CPU。 | ||
| 567 | +// 预期结果:编译在头文件校验前安全返回 UNSUPPORTED,不启动外部编译器。 | ||
| 568 | +TEST(HostCpuFusionCodegenST, CompilerRejectsMissingToolkitAndSelectsTargetCompiler) { | ||
| 569 | + | ||
| 570 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 571 | + | ||
| 572 | + const auto original_options = GetThreadLocalContext().GetAllGlobalOptions(); | ||
| 573 | + const ScopedEnvVar empty_opp("ASCEND_OPP_PATH", ""); | ||
| 574 | + const ScopedEnvVar empty_home("ASCEND_HOME_PATH", ""); | ||
| 575 | + ASSERT_TRUE(empty_opp.IsValid()); | ||
| 576 | + ASSERT_TRUE(empty_home.IsValid()); | ||
| 577 | + HostCpuFusionCompiler compiler; | ||
| 578 | + std::vector<uint8_t> so_data; | ||
| 579 | + | ||
| 580 | + GetThreadLocalContext().SetGlobalOption({{OPTION_HOST_ENV_CPU, "aarch64"}}); | ||
| 581 | + EXPECT_EQ(compiler.Compile("int value = 0;", so_data), UNSUPPORTED); | ||
| 582 | + GetThreadLocalContext().SetGlobalOption({{OPTION_HOST_ENV_CPU, "x86_64"}}); | ||
| 583 | + EXPECT_EQ(compiler.Compile("int value = 0;", so_data), UNSUPPORTED); | ||
| 584 | + GetThreadLocalContext().SetGlobalOption({{OPTION_HOST_ENV_CPU, "unsupported_cpu"}}); | ||
| 585 | + EXPECT_EQ(compiler.Compile("int value = 0;", so_data), UNSUPPORTED); | ||
| 586 | + GetThreadLocalContext().SetGlobalOption(original_options); | ||
| 587 | + | ||
| 588 | + const ScopedEnvVar invalid_opp("ASCEND_OPP_PATH", "/tmp/nonexistent/opp/"); | ||
| 589 | + const ScopedEnvVar invalid_home("ASCEND_HOME_PATH", "/tmp/nonexistent/home/"); | ||
| 590 | + ASSERT_TRUE(invalid_opp.IsValid()); | ||
| 591 | + ASSERT_TRUE(invalid_home.IsValid()); | ||
| 592 | + EXPECT_EQ(compiler.Compile("int value = 0;", so_data), UNSUPPORTED); | ||
| 593 | + | ||
| 594 | +} | ||
| 595 | + | ||
| 596 | +// 用例描述:覆盖融合源码生成器的输入校验、描述符序列化和属性序列化边界。 | ||
| 597 | +// 预置条件:Linux 环境可构造 GE 图;本用例不依赖实际设备执行。 | ||
| 598 | +// 测试步骤:构造有效融合区域,再逐项注入非法节点、边、名称、Shape 和属性。 | ||
| 599 | +// 预期结果:非法输入均返回 PARAM_INVALID 或 UNSUPPORTED,合法输入能生成稳定源码。 | ||
| 600 | +TEST(HostCpuFusionCodegenST, CoversCodegenValidationAndDescriptorBoundaries) { | ||
| 601 | + | ||
| 602 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 603 | + | ||
| 604 | + const auto graph = BuildCoverageChainGraph(); | ||
| 605 | + ASSERT_NE(graph, nullptr); | ||
| 606 | + const auto valid = BuildCoverageRegion(graph); | ||
| 193 | HostCpuFusionCodegen codegen; | 607 | HostCpuFusionCodegen codegen; |
| 194 | HostCpuFusionCodegenResult result; | 608 | HostCpuFusionCodegenResult result; |
| 609 | + ASSERT_EQ(codegen.Generate(valid, result), SUCCESS); | ||
| 610 | + EXPECT_FALSE(result.source.empty()); | ||
| 195 | 611 | ||
| 196 | auto invalid = valid; | 612 | auto invalid = valid; |
| 197 | - invalid.chain_id.clear(); | 613 | + invalid.nodes.resize(1U); |
| 198 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 614 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 199 | invalid = valid; | 615 | invalid = valid; |
| 200 | - invalid.chain_id = "9bad"; | 616 | + invalid.chain_id = "1bad"; |
| 201 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 617 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 202 | invalid = valid; | 618 | invalid = valid; |
| 203 | - invalid.chain_id = "has-dash"; | 619 | + invalid.chain_id = "bad-name"; |
| 204 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 620 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 205 | invalid = valid; | 621 | invalid = valid; |
| 206 | - invalid.chain_id.assign(160U, 'a'); | 622 | + invalid.chain_id.assign(200U, 'x'); |
| 207 | - EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | ||
| 208 | - invalid = valid; | ||
| 209 | - invalid.external_outputs.clear(); | ||
| 210 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 623 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 211 | invalid = valid; | 624 | invalid = valid; |
| 212 | invalid.nodes[0] = nullptr; | 625 | invalid.nodes[0] = nullptr; |
| 213 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 626 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 214 | invalid = valid; | 627 | invalid = valid; |
| 215 | - invalid.nodes[1] = invalid.nodes[0]; | 628 | + invalid.nodes.push_back(invalid.nodes.front()); |
| 216 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 629 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 217 | invalid = valid; | 630 | invalid = valid; |
| 218 | invalid.external_inputs[0] = nullptr; | 631 | invalid.external_inputs[0] = nullptr; |
| 219 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 632 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 220 | invalid = valid; | 633 | invalid = valid; |
| 221 | - invalid.external_inputs.push_back(invalid.external_inputs[0]); | 634 | + invalid.external_inputs.push_back(invalid.external_inputs.front()); |
| 222 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 635 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 223 | invalid = valid; | 636 | invalid = valid; |
| 224 | invalid.external_outputs[0].source = nullptr; | 637 | invalid.external_outputs[0].source = nullptr; |
| 225 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 638 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 226 | invalid = valid; | 639 | invalid = valid; |
| 227 | - invalid.external_outputs.push_back(invalid.external_outputs[0]); | 640 | + invalid.external_outputs.push_back(invalid.external_outputs.front()); |
| 641 | + EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | ||
| 642 | + invalid = valid; | ||
| 643 | + std::swap(invalid.nodes[0], invalid.nodes[1]); | ||
| 228 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); | 644 | EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 229 | 645 | ||
| 230 | invalid = valid; | 646 | invalid = valid; |
| 231 | - invalid.nodes[1]->GetOpDesc()->MutableOutputDesc(0)->SetShape(GeShape({-1})); | 647 | + invalid.external_inputs[0] = valid.nodes[0]->GetOutDataAnchor(0); |
| 232 | - EXPECT_EQ(codegen.Generate(invalid, result), UNSUPPORTED); | 648 | + EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 233 | invalid = valid; | 649 | invalid = valid; |
| 234 | - invalid.nodes[0]->GetOpDesc()->MutableOutputDesc(0)->SetShape(GeShape({-1})); | 650 | + invalid.external_outputs[0].source = graph->FindNode("data")->GetOutDataAnchor(0); |
| 235 | - EXPECT_EQ(codegen.Generate(invalid, result), UNSUPPORTED); | 651 | + EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 236 | invalid = valid; | 652 | invalid = valid; |
| 237 | - ASSERT_EQ(GraphUtils::RemoveEdge(invalid.nodes[0]->GetInDataAnchor(0)->GetPeerOutAnchor(), | 653 | + invalid.external_inputs.clear(); |
| 238 | - invalid.nodes[0]->GetInDataAnchor(0)), | 654 | + EXPECT_EQ(codegen.Generate(invalid, result), PARAM_INVALID); |
| 655 | + | ||
| 656 | + const auto missing_peer_graph = BuildCoverageChainGraph(); | ||
| 657 | + ASSERT_NE(missing_peer_graph, nullptr); | ||
| 658 | + ASSERT_EQ(GraphUtils::RemoveEdge(missing_peer_graph->FindNode("data")->GetOutDataAnchor(0), | ||
| 659 | + missing_peer_graph->FindNode("first")->GetInDataAnchor(0)), | ||
| 239 | GRAPH_SUCCESS); | 660 | GRAPH_SUCCESS); |
| 240 | - EXPECT_EQ(codegen.Generate(invalid, result), UNSUPPORTED); | 661 | + EXPECT_EQ(codegen.Generate(BuildCoverageRegion(missing_peer_graph), result), UNSUPPORTED); |
| 241 | 662 | ||
| 242 | - EXPECT_EQ(GetHostCpuFusionInputName(nullptr, 1U), "input_1_tensor"); | 663 | + const auto invalid_name_graph = BuildCoverageChainGraph(); |
| 243 | - const auto data = graph->FindNode("data"); | 664 | + ASSERT_NE(invalid_name_graph, nullptr); |
| 244 | - ASSERT_NE(data, nullptr); | 665 | + invalid_name_graph->FindNode("first")->GetOpDesc()->MutableAllInputName().clear(); |
| 245 | - data->GetOpDesc()->MutableAllOutputName().clear(); | 666 | + EXPECT_EQ(codegen.Generate(BuildCoverageRegion(invalid_name_graph), result), UNSUPPORTED); |
| 246 | - data->GetOpDesc()->MutableAllOutputName().emplace("with-dash", 0U); | ||
| 247 | - EXPECT_EQ(GetHostCpuFusionInputName(data->GetOutDataAnchor(0), 2U), "input_2_with_dash"); | ||
| 248 | -} | ||
| 249 | 667 | ||
| 250 | -TEST(HostCpuFusionCodegenST, CompilerHandlesMissingToolkitAndDiagnostics) { | 668 | + const auto invalid_output_name_graph = BuildCoverageChainGraph(); |
| 251 | -#if defined(__linux__) | 669 | + ASSERT_NE(invalid_output_name_graph, nullptr); |
| 252 | - EnvGuard home("ASCEND_HOME_PATH", ""); | 670 | + invalid_output_name_graph->FindNode("second")->GetOpDesc()->MutableAllOutputName().clear(); |
| 253 | - EnvGuard opp("ASCEND_OPP_PATH", ""); | 671 | + EXPECT_EQ(codegen.Generate(BuildCoverageRegion(invalid_output_name_graph), result), UNSUPPORTED); |
| 254 | - HostCpuFusionCompiler compiler; | ||
| 255 | - std::vector<uint8_t> so_data; | ||
| 256 | - EXPECT_EQ(compiler.Compile("int value = 0;", so_data), UNSUPPORTED); | ||
| 257 | - EXPECT_TRUE(so_data.empty()); | ||
| 258 | 672 | ||
| 259 | - const auto toolkit_home = GetToolkitHome(); | 673 | + const auto invalid_size_graph = BuildCoverageChainGraph(); |
| 260 | - EnvGuard valid_home("ASCEND_HOME_PATH", toolkit_home.c_str()); | 674 | + ASSERT_NE(invalid_size_graph, nullptr); |
| 261 | - EXPECT_EQ(compiler.Compile("this is invalid C++;", so_data), UNSUPPORTED); | 675 | + invalid_size_graph->FindNode("first")->GetOpDesc()->MutableOutputDesc(0)->SetShape( |
| 262 | - EXPECT_TRUE(so_data.empty()); | 676 | + GeShape({std::numeric_limits<int64_t>::max(), 2})); |
| 263 | - { | 677 | + EXPECT_EQ(codegen.Generate(BuildCoverageRegion(invalid_size_graph), result), UNSUPPORTED); |
| 264 | - EnvGuard no_home("ASCEND_HOME_PATH", ""); | 678 | + |
| 265 | - const auto toolkit_opp = GetToolkitOpp(toolkit_home); | 679 | + const auto scalar_graph = BuildCoverageChainGraph(); |
| 266 | - EnvGuard opp_only("ASCEND_OPP_PATH", toolkit_opp.c_str()); | 680 | + ASSERT_NE(scalar_graph, nullptr); |
| 267 | - EXPECT_EQ(compiler.Compile("", so_data), UNSUPPORTED); | 681 | + auto first_desc = scalar_graph->FindNode("first")->GetOpDesc(); |
| 682 | + first_desc->MutableOutputDesc(0)->SetShape(GeShape(std::vector<int64_t>{})); | ||
| 683 | + first_desc->MutableOutputDesc(0)->SetOriginShape(GeShape({3, 4})); | ||
| 684 | + ASSERT_EQ(first_desc->MutableOutputDesc(0)->SetShapeRange({{1, 3}, {2, 4}}), GRAPH_SUCCESS); | ||
| 685 | + ASSERT_TRUE(AttrUtils::SetInt(first_desc, "axis", 1)); | ||
| 686 | + ASSERT_TRUE(AttrUtils::SetFloat(first_desc, "scale", 2.0F)); | ||
| 687 | + ASSERT_TRUE(AttrUtils::SetBool(first_desc, "keep", true)); | ||
| 688 | + ASSERT_TRUE(AttrUtils::SetStr(first_desc, "label", "value\r\t")); | ||
| 689 | + ASSERT_TRUE(AttrUtils::SetListInt(first_desc, "sizes", {1, 2})); | ||
| 690 | + ASSERT_TRUE(AttrUtils::SetListFloat(first_desc, "ratios", {0.25F, 0.75F})); | ||
| 691 | + for (const auto &name : {"axis", "scale", "keep", "label", "sizes", "ratios"}) { | ||
| 692 | + first_desc->AppendIrAttrName(name); | ||
| 268 | } | 693 | } |
| 269 | -#else | 694 | + ASSERT_EQ(codegen.Generate(BuildCoverageRegion(scalar_graph), result), SUCCESS); |
| 270 | - GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | 695 | + EXPECT_NE(result.source.find("SetOriginShape"), std::string::npos); |
| 696 | + EXPECT_NE(result.source.find("SetShapeRange"), std::string::npos); | ||
| 697 | + EXPECT_NE(result.source.find("std::vector<int64_t>{1LL, 2LL}"), std::string::npos); | ||
| 698 | + EXPECT_NE(result.source.find("std::vector<float>{0.25F, 0.75F}"), std::string::npos); | ||
| 699 | + | ||
| 700 | + const auto unsupported_type_graph = BuildCoverageChainGraph(); | ||
| 701 | + ASSERT_NE(unsupported_type_graph, nullptr); | ||
| 702 | + unsupported_type_graph->FindNode("first")->GetOpDesc()->MutableOutputDesc(0)->SetShape( | ||
| 703 | + GeShape(std::vector<int64_t>{})); | ||
| 704 | + unsupported_type_graph->FindNode("first")->GetOpDesc()->MutableOutputDesc(0)->SetDataType(DT_UNDEFINED); | ||
| 705 | + EXPECT_EQ(codegen.Generate(BuildCoverageRegion(unsupported_type_graph), result), UNSUPPORTED); | ||
| 271 | 706 | ||
| 272 | } | 707 | } |
| 273 | 708 | ||
| 274 | -TEST(HostCpuFusionCodegenST, CommitsHostCpuFusionPassWithEmbeddedCustomOpSo) { | 709 | +// 用例描述:覆盖 HostCPU 融合 Pass 的候选拒绝和提交回滚路径。 |
| 275 | -#if defined(__linux__) | 710 | +// 预置条件:使用假的编译器返回合法 ELF,避免测试依赖 JIT 工具链。 |
| 276 | - const auto toolkit_home = GetToolkitHome(); | 711 | +// 测试步骤:构造候选链,分别注入不支持属性、控制边、Shape 边界和重复融合节点。 |
| 277 | - EnvGuard home("ASCEND_HOME_PATH", toolkit_home.c_str()); | 712 | +// 预期结果:Pass 保持原图不变,并返回对应状态。 |
| 278 | - EnvGuard opp("ASCEND_OPP_PATH", ""); | 713 | +TEST(HostCpuFusionCodegenST, CoversFusionPassCandidateAndRollbackPaths) { |
| 279 | - const auto graph = BuildPassGraph(); | 714 | +#if !defined(__linux__) |
| 715 | + GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 716 | + | ||
| 717 | + const auto graph = BuildCoverageChainGraph(); | ||
| 718 | + ASSERT_NE(graph, nullptr); | ||
| 719 | + HostCpuFusionPass pass(std::make_shared<StFakeCompiler>(), [](const std::string &) { return false; }); | ||
| 720 | + std::vector<std::vector<HostCpuFusionRegion> > components; | ||
| 721 | + EXPECT_EQ(pass.BuildFusionRegions(graph, components), NOT_CHANGED); | ||
| 722 | + EXPECT_TRUE(components.empty()); | ||
| 723 | + | ||
| 724 | + const auto control_graph = BuildCoverageChainGraph(); | ||
| 725 | + ASSERT_NE(control_graph, nullptr); | ||
| 726 | + ASSERT_EQ(GraphUtils::AddEdge(control_graph->FindNode("data")->GetOutControlAnchor(), | ||
| 727 | + control_graph->FindNode("first")->GetInControlAnchor()), | ||
| 728 | + GRAPH_SUCCESS); | ||
| 729 | + components.clear(); | ||
| 730 | + HostCpuFusionPass control_pass(std::make_shared<StFakeCompiler>(), [](const std::string &) { return true; }); | ||
| 731 | + EXPECT_EQ(control_pass.BuildFusionRegions(control_graph, components), NOT_CHANGED); | ||
| 732 | + EXPECT_TRUE(components.empty()); | ||
| 733 | + | ||
| 734 | + const auto shape_graph = BuildCoverageChainGraph(); | ||
| 735 | + ASSERT_NE(shape_graph, nullptr); | ||
| 736 | + shape_graph->FindNode("first")->GetOpDesc()->MutableOutputDesc(0)->SetShape(GeShape({-1})); | ||
| 737 | + components.clear(); | ||
| 738 | + EXPECT_EQ(control_pass.BuildFusionRegions(shape_graph, components), NOT_CHANGED); | ||
| 739 | + EXPECT_TRUE(components.empty()); | ||
| 740 | + | ||
| 741 | + const auto empty_graph = std::make_shared<ComputeGraph>("empty_host_cpu_coverage"); | ||
| 742 | + components.clear(); | ||
| 743 | + EXPECT_EQ(control_pass.BuildFusionRegions(nullptr, components), PARAM_INVALID); | ||
| 744 | + EXPECT_EQ(control_pass.BuildFusionRegions(empty_graph, components), PARAM_INVALID); | ||
| 745 | + | ||
| 746 | + const auto rollback_graph = BuildCoverageChainGraph(); | ||
| 747 | + ASSERT_NE(rollback_graph, nullptr); | ||
| 748 | + HostCpuFusionPass region_pass(std::make_shared<StFakeCompiler>(), [](const std::string &) { return true; }); | ||
| 749 | + ASSERT_EQ(region_pass.BuildFusionRegions(rollback_graph, components), SUCCESS); | ||
| 750 | + ASSERT_EQ(components.size(), 1U); | ||
| 751 | + ASSERT_EQ(components[0].size(), 1U); | ||
| 752 | + const std::string fused_name = std::string(kFusedHostCpuOpType) + "_" + components[0][0].chain_id; | ||
| 753 | + ASSERT_NE(rollback_graph->AddNode(std::make_shared<OpDesc>(fused_name, kFusedHostCpuOpType)), nullptr); | ||
| 280 | NodeEngineMap atomic_map; | 754 | NodeEngineMap atomic_map; |
| 281 | NodeEngineMap composite_map; | 755 | NodeEngineMap composite_map; |
| 282 | - HostCpuFusionPass pass(std::make_shared<MinimalCustomOpCompilerForPassSt>(), SupportAllForPassSt); | 756 | + EXPECT_EQ(region_pass.Run(rollback_graph, atomic_map, composite_map), FAILED); |
| 283 | - ASSERT_EQ(pass.Run(graph, atomic_map, composite_map), SUCCESS); | 757 | + EXPECT_NE(rollback_graph->FindNode("first"), nullptr); |
| 284 | - EXPECT_EQ(graph->FindNode("pass_first"), nullptr); | 758 | + EXPECT_NE(rollback_graph->FindNode("second"), nullptr); |
| 285 | - EXPECT_EQ(graph->FindNode("pass_second"), nullptr); | ||
| 286 | - EXPECT_EQ(graph->GetDirectNodesSize(), 3U); | ||
| 287 | - EXPECT_EQ(atomic_map.size(), 1U); | ||
| 288 | - EXPECT_EQ(composite_map.size(), 1U); | ||
| 289 | - | ||
| 290 | - GTEST_SKIP() << "HostCPU fusion JIT uses Linux memfd."; | ||
| 291 | 759 | ||
| 292 | } | 760 | } |
| 293 | - | ||
| 294 | } // namespace ge | 761 | } // namespace ge |
| @@ -17,7 +17,6 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | - | ||
| 21 | 20 | ||
| 22 | 21 | ||
| 23 | 22 | ||
| @@ -29,7 +28,6 @@ | |||
| 29 | 28 | ||
| 30 | 29 | ||
| 31 | 30 | ||
| 32 | - | ||
| 33 | 31 | ||
| 34 | 32 | ||
| 35 | 33 | ||
| @@ -41,7 +39,6 @@ | |||
| 41 | 39 | ||
| 42 | 40 | ||
| 43 | 41 | ||
| 44 | - | ||
| 45 | 42 | ||
| 46 | 43 | ||
| 47 | namespace ge { | 44 | namespace ge { |
| @@ -1071,61 +1068,4 @@ TEST_F(TestModelCustomOpsHelper, ge_root_model_target_host_env_and_cross_compile | |||
| 1071 | const std::string mismatch_cpu = (current_env_cpu == "x86_64") ? "aarch64" : "x86_64"; | 1068 | const std::string mismatch_cpu = (current_env_cpu == "x86_64") ? "aarch64" : "x86_64"; |
| 1072 | EXPECT_TRUE(ge_root_model.IsCrossCompileTarget(current_env_os, mismatch_cpu)); | 1069 | EXPECT_TRUE(ge_root_model.IsCrossCompileTarget(current_env_os, mismatch_cpu)); |
| 1073 | } | 1070 | } |
| 1074 | - | ||
| 1075 | -TEST_F(TestModelCustomOpsHelper, model_helper_saves_embedded_custom_op_so) { | ||
| 1076 | - auto root_graph = std::make_shared<ComputeGraph>("st_embedded_custom_so"); | ||
| 1077 | - auto ge_root_model = std::make_shared<GeRootModel>(); | ||
| 1078 | - ASSERT_EQ(ge_root_model->Initialize(root_graph), SUCCESS); | ||
| 1079 | - OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, ge_root_model->so_in_om_); | ||
| 1080 | - const auto custom_so = BuildCustomOpSoBinForSt("libst_embedded_custom.so", "st_custom_vendor", {'E', 'L', 'F'}); | ||
| 1081 | - ASSERT_NE(custom_so, nullptr); | ||
| 1082 | - ASSERT_TRUE(root_graph->SetExtAttr( | ||
| 1083 | - "bin_file_buffer", std::map<std::string, OpSoBinPtr>{{"st_custom_vendor/libst_embedded_custom.so", custom_so}})); | ||
| 1084 | - | ||
| 1085 | - ModelHelper model_helper; | ||
| 1086 | - EXPECT_EQ(model_helper.SaveCustomOpSoBin(ge_root_model), SUCCESS); | ||
| 1087 | -} | ||
| 1088 | - | ||
| 1089 | -TEST_F(TestModelCustomOpsHelper, ge_root_model_uses_embedded_host_cpu_fusion_so) { | ||
| 1090 | - RegisterCustomOpCreatorForSt(kCollectRootType, []() -> std::unique_ptr<BaseCustomOp> { | ||
| 1091 | - return std::make_unique<PortableOpForSerializeSuccess>(); | ||
| 1092 | - }); | ||
| 1093 | - const auto ge_root_model = CreateRootModelForCustomOps(kCollectRootType, "", false, false); | ||
| 1094 | - ASSERT_NE(ge_root_model, nullptr); | ||
| 1095 | - std::string current_env_os; | ||
| 1096 | - std::string current_env_cpu; | ||
| 1097 | - GetCurrentEnvWithFallbackForSt(current_env_os, current_env_cpu); | ||
| 1098 | - ScopedHostEnvOptionForSt host_env_guard(current_env_os, current_env_cpu); | ||
| 1099 | - ScopedEnvVarForSt custom_opp_guard("ASCEND_CUSTOM_OPP_PATH"); | ||
| 1100 | - ASSERT_EQ(mmSetEnv("ASCEND_CUSTOM_OPP_PATH", "", 1), EN_OK); | ||
| 1101 | - const auto embedded_so = | ||
| 1102 | - BuildCustomOpSoBinForSt("libStModelHelperCollectRootPortableOp.so", "host_cpu_fusion", {'E', 'L', 'F'}); | ||
| 1103 | - ASSERT_NE(embedded_so, nullptr); | ||
| 1104 | - ASSERT_TRUE(ge_root_model->GetRootGraph()->SetExtAttr( | ||
| 1105 | - "bin_file_buffer", | ||
| 1106 | - std::map<std::string, OpSoBinPtr>{{"host_cpu_fusion/libStModelHelperCollectRootPortableOp.so", embedded_so}})); | ||
| 1107 | - | ||
| 1108 | - ASSERT_EQ(ge_root_model->CheckAndSetNeedSoInOM(), SUCCESS); | ||
| 1109 | - EXPECT_TRUE(ge_root_model->GetCustomOpSoSet().empty()); | ||
| 1110 | - EXPECT_TRUE(OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)); | ||
| 1111 | -} | ||
| 1112 | - | ||
| 1113 | -TEST_F(TestModelCustomOpsHelper, engine_partitioner_merges_embedded_custom_op_so_buffers) { | ||
| 1114 | - EnginePartitioner partitioner; | ||
| 1115 | - const auto original_graph = std::make_shared<ComputeGraph>("st_original_so"); | ||
| 1116 | - auto merged_graph = std::make_shared<ComputeGraph>("st_merged_so"); | ||
| 1117 | - const auto original_so = BuildCustomOpSoBinForSt("libst_original.so", "host_cpu_fusion", {'A'}); | ||
| 1118 | - const auto existing_so = BuildCustomOpSoBinForSt("libst_existing.so", "host_cpu_fusion", {'B'}); | ||
| 1119 | - ASSERT_NE(original_so, nullptr); | ||
| 1120 | - ASSERT_NE(existing_so, nullptr); | ||
| 1121 | - ASSERT_TRUE(original_graph->SetExtAttr( | ||
| 1122 | - "bin_file_buffer", std::map<std::string, OpSoBinPtr>{{"host_cpu_fusion/libst_original.so", original_so}})); | ||
| 1123 | - ASSERT_TRUE(merged_graph->SetExtAttr( | ||
| 1124 | - "bin_file_buffer", std::map<std::string, OpSoBinPtr>{{"host_cpu_fusion/libst_existing.so", existing_so}})); | ||
| 1125 | - | ||
| 1126 | - ASSERT_EQ(partitioner.InheritOriginalAttr(original_graph, merged_graph), SUCCESS); | ||
| 1127 | - const auto so_buffer = merged_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer"); | ||
| 1128 | - ASSERT_NE(so_buffer, nullptr); | ||
| 1129 | - EXPECT_EQ(so_buffer->size(), 2U); | ||
| 1130 | -} | ||
| 1131 | } // namespace ge | 1071 | } // namespace ge |
| @@ -536,7 +536,6 @@ set(MULTI_PARTS_TEST_FILES | |||
| 536 | "graph/partition/graph_partition_unittest.cc" | 536 | "graph/partition/graph_partition_unittest.cc" |
| 537 | "graph/partition/stage_partition_unittest.cc" | 537 | "graph/partition/stage_partition_unittest.cc" |
| 538 | "graph/partition/optimizer/dynamic_data_flow_engine_reassign_unittest.cc" | 538 | "graph/partition/optimizer/dynamic_data_flow_engine_reassign_unittest.cc" |
| 539 | - "graph/partition/optimizer/host_cpu_fusion_codegen_unittest.cc" | ||
| 540 | "graph/partition/optimizer/host_cpu_fusion_pass_unittest.cc" | 539 | "graph/partition/optimizer/host_cpu_fusion_pass_unittest.cc" |
| 541 | "graph/partition/optimizer/hostcpu_engine_update_pass_unittest.cc" | 540 | "graph/partition/optimizer/hostcpu_engine_update_pass_unittest.cc" |
| 542 | "graph/manager/graph_manager_unittest.cc" | 541 | "graph/manager/graph_manager_unittest.cc" |
| @@ -27,7 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | - | ||
| 31 | 30 | ||
| 32 | 31 | ||
| 33 | 32 | ||
| @@ -2796,54 +2795,6 @@ TEST_F(UtestModelHelper, SaveAutofuseSoBinWithExtAttrPopulatesOpSoStore) { | |||
| 2796 | EXPECT_EQ(so_bins[0U]->GetSoBinType(), SoBinType::kAutofuse); | 2795 | EXPECT_EQ(so_bins[0U]->GetSoBinType(), SoBinType::kAutofuse); |
| 2797 | } | 2796 | } |
| 2798 | 2797 | ||
| 2799 | -TEST_F(UtestModelHelper, SaveCustomOpSoBinWithExtAttrStoresOnlyCustomOpSo) { | ||
| 2800 | - auto root_graph = std::make_shared<ComputeGraph>("root_graph_custom_so_ext"); | ||
| 2801 | - auto ge_root_model = std::make_shared<GeRootModel>(); | ||
| 2802 | - ASSERT_EQ(ge_root_model->Initialize(root_graph), SUCCESS); | ||
| 2803 | - OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, ge_root_model->so_in_om_); | ||
| 2804 | - | ||
| 2805 | - const auto custom_so = | ||
| 2806 | - BuildOpSoBinForModelHelperUt("libcustom_repack_ut.so", "custom_vendor_ut", {0x10U, 0x20U}, SoBinType::kCustomOp); | ||
| 2807 | - const auto autofuse_so = BuildOpSoBinForModelHelperUt("libautofuse_repack_ut.so", "autofuse_vendor_ut", | ||
| 2808 | - {0x30U, 0x40U}, SoBinType::kAutofuse); | ||
| 2809 | - ASSERT_NE(custom_so, nullptr); | ||
| 2810 | - ASSERT_NE(autofuse_so, nullptr); | ||
| 2811 | - std::map<std::string, OpSoBinPtr> so_buffer; | ||
| 2812 | - so_buffer.emplace("custom_vendor_ut/libcustom_repack_ut.so", custom_so); | ||
| 2813 | - so_buffer.emplace("autofuse_vendor_ut/libautofuse_repack_ut.so", autofuse_so); | ||
| 2814 | - ASSERT_TRUE(root_graph->SetExtAttr("bin_file_buffer", so_buffer)); | ||
| 2815 | - | ||
| 2816 | - ModelHelper model_helper; | ||
| 2817 | - ASSERT_EQ(model_helper.SaveCustomOpSoBin(ge_root_model), SUCCESS); | ||
| 2818 | - const auto so_bins = model_helper.op_so_store_.GetSoBin(); | ||
| 2819 | - ASSERT_EQ(so_bins.size(), 1U); | ||
| 2820 | - EXPECT_EQ(so_bins[0U]->GetSoName(), "libcustom_repack_ut.so"); | ||
| 2821 | - EXPECT_EQ(so_bins[0U]->GetSoBinType(), SoBinType::kCustomOp); | ||
| 2822 | -} | ||
| 2823 | - | ||
| 2824 | -TEST_F(UtestModelHelper, EmbeddedHostCpuFusionSoSkipsPortableSoPathCollect) { | ||
| 2825 | - RegisterCustomOpCreatorForModelHelperUt(kPortableOpTypeForModelHelper, []() -> std::unique_ptr<BaseCustomOp> { | ||
| 2826 | - return std::make_unique<ModelHelperPortableOpForUt>(); | ||
| 2827 | - }); | ||
| 2828 | - const auto ge_root_model = | ||
| 2829 | - CreateGeRootModelForModelHelperUt(kPortableOpTypeForModelHelper, kPortableOpTypeForModelHelper); | ||
| 2830 | - ASSERT_NE(ge_root_model, nullptr); | ||
| 2831 | - ScopedHostEnvForModelHelperUt host_env_guard("linux", GetCurArch()); | ||
| 2832 | - ScopedEnvVarForModelHelperUt custom_opp_guard(kEnvNameCustom); | ||
| 2833 | - ASSERT_EQ(mmSetEnv(kEnvNameCustom, "", 1), EN_OK); | ||
| 2834 | - | ||
| 2835 | - const auto embedded_so = BuildOpSoBinForModelHelperUt("libModelHelperPortableOpForUt.so", "host_cpu_fusion", | ||
| 2836 | - {0x7FU, 0x45U, 0x4CU, 0x46U}, SoBinType::kCustomOp); | ||
| 2837 | - ASSERT_NE(embedded_so, nullptr); | ||
| 2838 | - std::map<std::string, OpSoBinPtr> so_buffer; | ||
| 2839 | - so_buffer.emplace("host_cpu_fusion/libModelHelperPortableOpForUt.so", embedded_so); | ||
| 2840 | - ASSERT_TRUE(ge_root_model->GetRootGraph()->SetExtAttr("bin_file_buffer", so_buffer)); | ||
| 2841 | - | ||
| 2842 | - ASSERT_EQ(ge_root_model->CheckAndSetNeedSoInOM(), SUCCESS); | ||
| 2843 | - EXPECT_TRUE(ge_root_model->GetCustomOpSoSet().empty()); | ||
| 2844 | - EXPECT_TRUE(OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)); | ||
| 2845 | -} | ||
| 2846 | - | ||
| 2847 | // 边界用例:ExtAttr("bin_file_buffer")存在但map为空时不应异常, | 2798 | // 边界用例:ExtAttr("bin_file_buffer")存在但map为空时不应异常, |
| 2848 | // op_so_store_应保持空。 | 2799 | // op_so_store_应保持空。 |
| 2849 | TEST_F(UtestModelHelper, SaveAutofuseSoBinWithEmptyExtAttrDoesNotAddToStore) { | 2800 | TEST_F(UtestModelHelper, SaveAutofuseSoBinWithEmptyExtAttrDoesNotAddToStore) { |
| @@ -35,7 +35,6 @@ | |||
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | - | ||
| 39 | 38 | ||
| 40 | namespace ge { | 39 | namespace ge { |
| 41 | namespace airut { | 40 | namespace airut { |
| @@ -358,60 +357,6 @@ TEST_F(UtestGraphPartition, merge_overflow_attr) { | |||
| 358 | ASSERT_EQ(EnginePartitioner.global_workspace_type_, 0); | 357 | ASSERT_EQ(EnginePartitioner.global_workspace_type_, 0); |
| 359 | } | 358 | } |
| 360 | 359 | ||
| 361 | -TEST_F(UtestGraphPartition, inherit_original_attr_preserves_custom_op_so_buffer) { | ||
| 362 | - EnginePartitioner partitioner; | ||
| 363 | - const auto original_graph = std::make_shared<ComputeGraph>("original"); | ||
| 364 | - auto merged_graph = std::make_shared<ComputeGraph>("merged"); | ||
| 365 | - | ||
| 366 | - auto so_data = std::make_unique<char_t[]>(4U); | ||
| 367 | - so_data[0] = 'E'; | ||
| 368 | - so_data[1] = 'L'; | ||
| 369 | - so_data[2] = 'F'; | ||
| 370 | - so_data[3] = '\0'; | ||
| 371 | - const auto so_bin = | ||
| 372 | - MakeShared<OpSoBin>("libFusedHostCpu_test.so", "host_cpu_fusion", std::move(so_data), 4U, SoBinType::kCustomOp); | ||
| 373 | - ASSERT_NE(so_bin, nullptr); | ||
| 374 | - std::map<std::string, OpSoBinPtr> so_buffer; | ||
| 375 | - so_buffer.emplace("host_cpu_fusion/libFusedHostCpu_test.so", so_bin); | ||
| 376 | - ASSERT_TRUE(original_graph->SetExtAttr("bin_file_buffer", so_buffer)); | ||
| 377 | - | ||
| 378 | - ASSERT_EQ(partitioner.InheritOriginalAttr(original_graph, merged_graph), SUCCESS); | ||
| 379 | - const auto inherited = merged_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer"); | ||
| 380 | - ASSERT_NE(inherited, nullptr); | ||
| 381 | - ASSERT_EQ(inherited->size(), 1U); | ||
| 382 | - const auto iter = inherited->find("host_cpu_fusion/libFusedHostCpu_test.so"); | ||
| 383 | - ASSERT_NE(iter, inherited->end()); | ||
| 384 | - ASSERT_NE(iter->second, nullptr); | ||
| 385 | - EXPECT_EQ(iter->second->GetSoBinType(), SoBinType::kCustomOp); | ||
| 386 | -} | ||
| 387 | - | ||
| 388 | -TEST_F(UtestGraphPartition, inherit_original_attr_merges_existing_custom_op_so_buffer) { | ||
| 389 | - EnginePartitioner partitioner; | ||
| 390 | - const auto original_graph = std::make_shared<ComputeGraph>("original_with_so"); | ||
| 391 | - auto merged_graph = std::make_shared<ComputeGraph>("merged_with_so"); | ||
| 392 | - auto original_data = std::make_unique<char_t[]>(1U); | ||
| 393 | - original_data[0] = 'A'; | ||
| 394 | - auto existing_data = std::make_unique<char_t[]>(1U); | ||
| 395 | - existing_data[0] = 'B'; | ||
| 396 | - const auto original_so = | ||
| 397 | - MakeShared<OpSoBin>("liboriginal.so", "host_cpu_fusion", std::move(original_data), 1U, SoBinType::kCustomOp); | ||
| 398 | - const auto existing_so = | ||
| 399 | - MakeShared<OpSoBin>("libexisting.so", "host_cpu_fusion", std::move(existing_data), 1U, SoBinType::kCustomOp); | ||
| 400 | - ASSERT_NE(original_so, nullptr); | ||
| 401 | - ASSERT_NE(existing_so, nullptr); | ||
| 402 | - ASSERT_TRUE(original_graph->SetExtAttr( | ||
| 403 | - "bin_file_buffer", std::map<std::string, OpSoBinPtr>{{"host_cpu_fusion/liboriginal.so", original_so}})); | ||
| 404 | - ASSERT_TRUE(merged_graph->SetExtAttr( | ||
| 405 | - "bin_file_buffer", std::map<std::string, OpSoBinPtr>{{"host_cpu_fusion/libexisting.so", existing_so}})); | ||
| 406 | - | ||
| 407 | - ASSERT_EQ(partitioner.InheritOriginalAttr(original_graph, merged_graph), SUCCESS); | ||
| 408 | - const auto inherited = merged_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer"); | ||
| 409 | - ASSERT_NE(inherited, nullptr); | ||
| 410 | - EXPECT_EQ(inherited->size(), 2U); | ||
| 411 | - EXPECT_EQ(inherited->at("host_cpu_fusion/liboriginal.so"), original_so); | ||
| 412 | - EXPECT_EQ(inherited->at("host_cpu_fusion/libexisting.so"), existing_so); | ||
| 413 | -} | ||
| 414 | - | ||
| 415 | TEST_F(UtestGraphPartition, merge_after_sub_graph_optimization_test_with_func_sub_graph) { | 360 | TEST_F(UtestGraphPartition, merge_after_sub_graph_optimization_test_with_func_sub_graph) { |
| 416 | EnginePartitioner EnginePartitioner; | 361 | EnginePartitioner EnginePartitioner; |
| 417 | ComputeGraphPtr graph = std::make_shared<ComputeGraph>("default"); | 362 | ComputeGraphPtr graph = std::make_shared<ComputeGraph>("default"); |