已合并
【feat】: HostCPU 融合 Codegen 迁移至标准 CustomOp #4669
ZhuXincheng创建于 6 天前
【feat】: HostCPU 融合 Codegen 迁移至标准 CustomOp #4669
已合并
ZhuXincheng创建于 6 天前
38 个文件变更+1662-4548
@@ -606,7 +606,9 @@ 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- op_so_store_.AddKernel(bin_entry.second);609+ if ((bin_entry.second != nullptr) && (bin_entry.second->GetSoBinType() == SoBinType::kAutofuse)) {
610+ op_so_store_.AddKernel(bin_entry.second);
611+ }
610 }612 }
611 return SUCCESS;613 return SUCCESS;
612 }614 }
@@ -623,8 +625,21 @@ Status ModelHelper::SaveCustomOpSoBin(const GeRootModelPtr &ge_root_model) {
623 if (!OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)) {625 if (!OpSoStoreUtils::IsSoBinType(ge_root_model->GetSoInOmFlag(), SoBinType::kCustomOp)) {
624 return SUCCESS;626 return SUCCESS;
625 }627 }
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+ }
626 GE_ASSERT_SUCCESS(LoadAndStoreOppSo(ge_root_model->GetCustomOpSoSet(), SoBinType::kCustomOp));640 GE_ASSERT_SUCCESS(LoadAndStoreOppSo(ge_root_model->GetCustomOpSoSet(), SoBinType::kCustomOp));
627- GELOGI("[CustomOp]Save %zu custom op so to OpSoStore success.", ge_root_model->GetCustomOpSoSet().size());641+ GELOGI("[CustomOp]Save %zu path-based and %zu embedded custom op so to OpSoStore success.",
642+ ge_root_model->GetCustomOpSoSet().size(), embedded_so_num);
628 return SUCCESS;643 return SUCCESS;
629}644}
630 645 
@@ -32,6 +32,8 @@
32#include "external/ge_common/ge_common_api_types.h"32#include "external/ge_common/ge_common_api_types.h"
33#include "external/graph/custom_op.h"33#include "external/graph/custom_op.h"
34#include "graph/custom_op/cast.h"34#include "graph/custom_op/cast.h"
35+#include "framework/common/host_cpu_fusion_attr.h"
36+#include "graph/op_so_bin.h"
35#include "common/om2/om2_model_data.h"37#include "common/om2/om2_model_data.h"
36 38 
37namespace ge {39namespace ge {
@@ -171,6 +173,37 @@ Status CollectCustomOpTypesFromGraph(const ComputeGraphPtr &graph, const CustomO
171 }173 }
172 return SUCCESS;174 return SUCCESS;
173}175}
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+ 
191+size_t GetEmbeddedCustomOpSoNum(const ComputeGraphPtr &root_graph) {
192+ if (root_graph == nullptr) {
193+ return 0U;
194+ }
195+ const auto so_buffer = root_graph->GetExtAttr<std::map<std::string, OpSoBinPtr>>("bin_file_buffer");
196+ if (so_buffer == nullptr) {
197+ return 0U;
198+ }
199+ size_t embedded_custom_so_num = 0U;
200+ for (const auto &entry : *so_buffer) {
201+ if ((entry.second != nullptr) && (entry.second->GetSoBinType() == SoBinType::kCustomOp)) {
202+ ++embedded_custom_so_num;
203+ }
204+ }
205+ return embedded_custom_so_num;
206+}
174} // namespace207} // namespace
175Status GeRootModel::Initialize(const ComputeGraphPtr &root_graph) {208Status GeRootModel::Initialize(const ComputeGraphPtr &root_graph) {
176 GE_ASSERT_NOTNULL(root_graph);209 GE_ASSERT_NOTNULL(root_graph);
@@ -379,14 +412,7 @@ Status GeRootModel::ResolvePortableOpSoPath(const std::string &op_type, Portable
379 return SUCCESS;412 return SUCCESS;
380}413}
381 414 
382-Status GeRootModel::CheckAndSetCustomOpSo() {415+Status GeRootModel::CollectCustomOpTypesForRootModel(std::set<std::string> &used_custom_op_types) const {
383- GE_ASSERT_NOTNULL(root_graph_);
384- GE_ASSERT_NOTNULL(custom_op_registry_);
385- std::string target_os;
386- std::string target_cpu;
387- GE_ASSERT_SUCCESS(GetTargetHostEnv(target_os, target_cpu), "Get target host env failed.");
388- const bool is_cross_compile = IsCrossCompileTarget(target_os, target_cpu);
389- std::set<std::string> used_custom_op_types;
390 GE_ASSERT_SUCCESS(CollectCustomOpTypesFromGraph(root_graph_, custom_op_registry_, used_custom_op_types));416 GE_ASSERT_SUCCESS(CollectCustomOpTypesFromGraph(root_graph_, custom_op_registry_, used_custom_op_types));
391 for (const auto &item : subgraph_instance_name_to_model_) {417 for (const auto &item : subgraph_instance_name_to_model_) {
392 const auto &ge_model = item.second;418 const auto &ge_model = item.second;
@@ -395,8 +421,11 @@ Status GeRootModel::CheckAndSetCustomOpSo() {
395 }421 }
396 GE_ASSERT_SUCCESS(CollectCustomOpTypesFromGraph(ge_model->GetGraph(), custom_op_registry_, used_custom_op_types));422 GE_ASSERT_SUCCESS(CollectCustomOpTypesFromGraph(ge_model->GetGraph(), custom_op_registry_, used_custom_op_types));
397 }423 }
424+ return SUCCESS;
425+}
398 426 
399- bool has_portable_custom_op = false;427+Status GeRootModel::CollectPortableCustomOpSo(const std::set<std::string> &used_custom_op_types,
428+ const bool is_cross_compile, bool &has_portable_custom_op) {
400 for (const auto &op_type : used_custom_op_types) {429 for (const auto &op_type : used_custom_op_types) {
401 auto *portable_op = CustomOpCast<PortableOp>(430 auto *portable_op = CustomOpCast<PortableOp>(
402 custom_op_registry_->GetCustomOpCommonCapability(AscendString(op_type.c_str()), CustomOpCapability::kPortable));431 custom_op_registry_->GetCustomOpCommonCapability(AscendString(op_type.c_str()), CustomOpCapability::kPortable));
@@ -409,6 +438,11 @@ Status GeRootModel::CheckAndSetCustomOpSo() {
409 continue;438 continue;
410 }439 }
411 440 
441+ if (IsEmbeddedHostCpuFusionSo(root_graph_, op_type)) {
442+ GELOGI("[CustomOp] op[%s] uses embedded HostCPU fusion SO, skip path collect.", op_type.c_str());
443+ continue;
444+ }
445+ 
412 std::string so_path;446 std::string so_path;
413 GE_ASSERT_SUCCESS(ResolvePortableOpSoPath(op_type, portable_op, so_path),447 GE_ASSERT_SUCCESS(ResolvePortableOpSoPath(op_type, portable_op, so_path),
414 "Resolve custom op so path failed for op[%s].", op_type.c_str());448 "Resolve custom op so path failed for op[%s].", op_type.c_str());
@@ -416,7 +450,27 @@ Status GeRootModel::CheckAndSetCustomOpSo() {
416 (void)custom_op_so_set_.insert(so_path);450 (void)custom_op_so_set_.insert(so_path);
417 GELOGI("[CustomOp] Collect custom op so[%s] for op[%s].", so_path.c_str(), op_type.c_str());451 GELOGI("[CustomOp] Collect custom op so[%s] for op[%s].", so_path.c_str(), op_type.c_str());
418 }452 }
453+ return SUCCESS;
454+}
419 455 
456+Status GeRootModel::CheckAndSetCustomOpSo() {
457+ GE_ASSERT_NOTNULL(root_graph_);
458+ GE_ASSERT_NOTNULL(custom_op_registry_);
459+ std::string target_os;
460+ std::string target_cpu;
461+ GE_ASSERT_SUCCESS(GetTargetHostEnv(target_os, target_cpu), "Get target host env failed.");
462+ const bool is_cross_compile = IsCrossCompileTarget(target_os, target_cpu);
463+ std::set<std::string> used_custom_op_types;
464+ const auto collect_custom_op_status = CollectCustomOpTypesForRootModel(used_custom_op_types);
465+ if (collect_custom_op_status != SUCCESS) {
466+ return collect_custom_op_status;
467+ }
468+ bool has_portable_custom_op = false;
469+ const auto collect_portable_op_status =
470+ CollectPortableCustomOpSo(used_custom_op_types, is_cross_compile, has_portable_custom_op);
471+ if (collect_portable_op_status != SUCCESS) {
472+ return collect_portable_op_status;
473+ }
420 if (is_cross_compile && has_portable_custom_op) {474 if (is_cross_compile && has_portable_custom_op) {
421 GE_ASSERT_SUCCESS(CollectCustomOpSoFromCustomOppPath(target_os, target_cpu),475 GE_ASSERT_SUCCESS(CollectCustomOpSoFromCustomOppPath(target_os, target_cpu),
422 "Collect custom op so from ASCEND_CUSTOM_OPP_PATH failed.");476 "Collect custom op so from ASCEND_CUSTOM_OPP_PATH failed.");
@@ -425,7 +479,12 @@ Status GeRootModel::CheckAndSetCustomOpSo() {
425 if (!custom_op_so_set_.empty()) {479 if (!custom_op_so_set_.empty()) {
426 OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_);480 OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_);
427 }481 }
428- GELOGI("[CustomOp]The num of so is %zu.", custom_op_so_set_.size());482+ const size_t embedded_custom_so_num = GetEmbeddedCustomOpSoNum(root_graph_);
483+ if (embedded_custom_so_num > 0U) {
484+ OpSoStoreUtils::SetSoBinType(SoBinType::kCustomOp, so_in_om_);
485+ }
486+ GELOGI("[CustomOp]The num of path-based so is %zu, embedded so is %zu.", custom_op_so_set_.size(),
487+ embedded_custom_so_num);
429 return SUCCESS;488 return SUCCESS;
430}489}
431 490 
@@ -14,6 +14,7 @@
14#include <mutex>14#include <mutex>
15#include <map>15#include <map>
16#include <sstream>16#include <sstream>
17+#include <set>
17#include "framework/common/ge_types.h"18#include "framework/common/ge_types.h"
18#include "ge/ge_graph_compile_summary.h"19#include "ge/ge_graph_compile_summary.h"
19#include "ge/ge_allocator.h"20#include "ge/ge_allocator.h"
@@ -222,6 +223,9 @@ class GeRootModel : public std::enable_shared_from_this<GeRootModel> {
222 Status CheckAndSetOpMasterDevice();223 Status CheckAndSetOpMasterDevice();
223 Status CheckAndSetAutofuseSo();224 Status CheckAndSetAutofuseSo();
224 Status CheckAndSetCustomOpSo();225 Status CheckAndSetCustomOpSo();
226+ Status CollectCustomOpTypesForRootModel(std::set<std::string> &used_custom_op_types) const;
227+ Status CollectPortableCustomOpSo(const std::set<std::string> &used_custom_op_types, bool is_cross_compile,
228+ bool &has_portable_custom_op);
225 Status GetTargetHostEnv(std::string &host_env_os, std::string &host_env_cpu) const;229 Status GetTargetHostEnv(std::string &host_env_os, std::string &host_env_cpu) const;
226 bool IsCrossCompileTarget(const std::string &target_os, const std::string &target_cpu) const;230 bool IsCrossCompileTarget(const std::string &target_os, const std::string &target_cpu) const;
227 Status ResolvePortableOpSoPath(const std::string &op_type, PortableOp *portable_op, std::string &so_path) const;231 Status ResolvePortableOpSoPath(const std::string &op_type, PortableOp *portable_op, std::string &so_path) const;
@@ -25,7 +25,7 @@ namespace {
25const std::string kConstantFoldingName = "libconstant_folding_ops.so";25const std::string kConstantFoldingName = "libconstant_folding_ops.so";
26const std::string kOpsHostCpuName = "libops_host_cpu.so";26const std::string kOpsHostCpuName = "libops_host_cpu.so";
27const std::string kAicpuConstFoldingName = "libaicpu_const_folding.so";27const std::string kAicpuConstFoldingName = "libaicpu_const_folding.so";
28-const char *const kIsFusedCpuKernelSupported = "IsCpuConstantFoldingFusedOpSupported";28+constexpr char kAicpuHostFindFunc[] = "AicpuHostFindFunc";
29 29 
30Status GetDataNumber(const GeTensorDesc &out_desc, uint64_t &data_num) {30Status 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,15 +141,13 @@ void HostCpuEngine::Finalize() const {
141 GELOGI("start HostCpuEngine::Finalize");141 GELOGI("start HostCpuEngine::Finalize");
142}142}
143 143 
144-bool HostCpuEngine::IsFusedCpuKernelSupported(const std::string &op_type) const {144+bool HostCpuEngine::IsHostKernelSupported(const std::string &op_type) const {
145- if (is_fused_cpu_kernel_supported_ == nullptr) {145+ if (host_kernel_finder_ == nullptr) {
146- GELOGD("HostCPU fused-kernel support query is unavailable for op[%s].", op_type.c_str());146+ GELOGD("HostCPU Gert HostKernel finder is unavailable for op[%s].", op_type.c_str());
147 return false;147 return false;
148 }148 }
149- const bool supported = is_fused_cpu_kernel_supported_(op_type.c_str()) == 1;149+ const bool supported = host_kernel_finder_(op_type) != nullptr;
150- if (!supported) {150+ GELOGD("HostCPU Gert HostKernel query: op[%s], supported[%d].", op_type.c_str(), static_cast<int32_t>(supported));
151- GELOGD("HostCPU fused-kernel support query rejected op[%s].", op_type.c_str());
152- }
153 return supported;151 return supported;
154}152}
155 153 
@@ -308,14 +306,11 @@ Status HostCpuEngine::LoadLib(const std::string &lib_path, bool invoke_init) {
308 GELOGI("Lib: %s has been opened", lib_path.c_str());306 GELOGI("Lib: %s has been opened", lib_path.c_str());
309 if (lib_path.find(kConstantFoldingName) != lib_path.npos) {307 if (lib_path.find(kConstantFoldingName) != lib_path.npos) {
310 constant_folding_handle_ = handle;308 constant_folding_handle_ = handle;
311- }309+ host_kernel_finder_ = reinterpret_cast<HostKernelFinder>(mmDlsym(handle, kAicpuHostFindFunc));
312- if (lib_path.find(kAicpuConstFoldingName) != lib_path.npos) {310+ if (host_kernel_finder_ == nullptr) {
313- is_fused_cpu_kernel_supported_ =
314- reinterpret_cast<int32_t (*)(const char *)>(mmDlsym(handle, kIsFusedCpuKernelSupported));
315- if (is_fused_cpu_kernel_supported_ == nullptr) {
316 const char_t *reason = mmDlerror();311 const char_t *reason = mmDlerror();
317 reason = (reason == nullptr) ? "" : reason;312 reason = (reason == nullptr) ? "" : reason;
318- GELOGW("Fused HostCPU support query symbol is unavailable in lib: %s, reason = %s", lib_path.c_str(), reason);313+ GELOGW("Gert HostKernel finder is unavailable in lib: %s, reason = %s", lib_path.c_str(), reason);
319 }314 }
320 }315 }
321 (void)lib_handles_.emplace_back(handle);316 (void)lib_handles_.emplace_back(handle);
@@ -19,6 +19,10 @@
19#include "graph/operator.h"19#include "graph/operator.h"
20#include "graph_metadef/register/graph_register.h"20#include "graph_metadef/register/graph_register.h"
21 21 
22+namespace gert {
23+class KernelContext;
24+}
25+ 
22namespace ge {26namespace ge {
23class HostCpuEngine {27class HostCpuEngine {
24 public:28 public:
@@ -37,9 +41,13 @@ class HostCpuEngine {
37 return constant_folding_handle_;41 return constant_folding_handle_;
38 }42 }
39 43 
40- bool IsFusedCpuKernelSupported(const std::string &op_type) const;44+ // 查询 libconstant_folding_ops.so 的 Gert HostKernel 路由。只要 op_type 能找到函数即可参与融合。
45+ bool IsHostKernelSupported(const std::string &op_type) const;
41 46 
42 private:47 private:
48+ using HostKernelFunc = graphStatus (*)(gert::KernelContext *);
49+ using HostKernelFinder = HostKernelFunc (*)(std::string);
50+ 
43 HostCpuEngine() = default;51 HostCpuEngine() = default;
44 52 
45 void *DlopenLib(const std::string &lib_path) const;53 void *DlopenLib(const std::string &lib_path) const;
@@ -63,7 +71,7 @@ class HostCpuEngine {
63 std::mutex mu_;71 std::mutex mu_;
64 std::vector<void *> lib_handles_;72 std::vector<void *> lib_handles_;
65 void *constant_folding_handle_ = nullptr;73 void *constant_folding_handle_ = nullptr;
66- int32_t (*is_fused_cpu_kernel_supported_)(const char *) = nullptr;74+ HostKernelFinder host_kernel_finder_ = nullptr;
67 bool initialized_ = false;75 bool initialized_ = false;
68};76};
69} // namespace ge77} // namespace ge
@@ -18,11 +18,7 @@
18#include <vector>18#include <vector>
19#include <set>19#include <set>
20#include <string>20#include <string>
21-#include <memory>
22-#include <new>
23-#include <limits>
24#include <unordered_map>21#include <unordered_map>
25-#include <unordered_set>
26#include <dirent.h>22#include <dirent.h>
27#include <dlfcn.h>23#include <dlfcn.h>
28#include <cstring>24#include <cstring>
@@ -58,8 +54,6 @@ const char *const kExcludedConstantFoldingSo = "libconstant_folding_ops.so";
58const char *const kSymGetAllRegisteredOpTypesV2 = "GetAllRegisteredOpTypesV2";54const char *const kSymGetAllRegisteredOpTypesV2 = "GetAllRegisteredOpTypesV2";
59const char *const kSymIsRegisteredV2 = "IsRegisteredV2";55const char *const kSymIsRegisteredV2 = "IsRegisteredV2";
60const char *const kSymRunCpuKernelV2 = "RunCpuKernelV2";56const char *const kSymRunCpuKernelV2 = "RunCpuKernelV2";
61-constexpr uint32_t kFusedHostCpuShapeChanged = 1U;
62-constexpr uint32_t kFusedHostCpuDataChanged = 2U;
63 57 
64using AttrValueMap = google::protobuf::Map<string, aicpuops::AttrValue>;58using AttrValueMap = google::protobuf::Map<string, aicpuops::AttrValue>;
65 59 
@@ -75,62 +69,7 @@ struct V2ModuleBinding {
75 std::string so_name;69 std::string so_name;
76};70};
77 71 
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- 
132std::vector<V2ModuleBinding> g_v2_bindings;72std::vector<V2ModuleBinding> g_v2_bindings;
133-std::unordered_set<std::string> g_v1_op_types;
134// op_type->binding反向索引, Init阶段一次性构建, 运行期只读。73// op_type->binding反向索引, Init阶段一次性构建, 运行期只读。
135std::unordered_map<std::string, const V2ModuleBinding *> g_v2_op_index;74std::unordered_map<std::string, const V2ModuleBinding *> g_v2_op_index;
136 75 
@@ -156,27 +95,6 @@ void ConvertGeToAicpuTensor(const ge::GeTensorDesc &tensor_desc, const std::stri
156 static_cast<int>(tensor_desc.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize());95 static_cast<int>(tensor_desc.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize());
157}96}
158 97 
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- 
180int32_t AddStringAttrToNodeDef(const ge::Operator &op, const char *name, [[maybe_unused]] aicpuops::NodeDef node_def,98int32_t AddStringAttrToNodeDef(const ge::Operator &op, const char *name, [[maybe_unused]] aicpuops::NodeDef node_def,
181 aicpuops::AttrValue &attr_value) {99 aicpuops::AttrValue &attr_value) {
182 std::string s;100 std::string s;
@@ -608,8 +526,6 @@ __attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::Hos
608 526 
609 std::vector<std::string> ops = aicpu::CpuKernelRegister::Instance().GetAllRegisteredOpTypes();527 std::vector<std::string> ops = aicpu::CpuKernelRegister::Instance().GetAllRegisteredOpTypes();
610 AICPUE_LOGI("Registered V1 ops: %llu", static_cast<uint64_t>(ops.size()));528 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());
613 RegisterHostCpuOp(ops, create_fn);529 RegisterHostCpuOp(ops, create_fn);
614 530 
615 // 枚举每个ops so的V2算子, 同时构建op_type->binding反向索引。531 // 枚举每个ops so的V2算子, 同时构建op_type->binding反向索引。
@@ -656,7 +572,7 @@ int32_t BuildInputTensors(const ge::OpDescPtr &op_desc, const std::map<std::stri
656 return 0;572 return 0;
657}573}
658 574 
659-int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, const std::map<std::string, ge::Tensor> &outputs,575+int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, std::map<std::string, ge::Tensor> &outputs,
660 const char *op_type, aicpuops::NodeDef &node_def) {576 const char *op_type, aicpuops::NodeDef &node_def) {
661 uint32_t count = static_cast<uint32_t>(op_desc->GetOutputsSize());577 uint32_t count = static_cast<uint32_t>(op_desc->GetOutputsSize());
662 for (uint32_t i = 0; i < count; ++i) {578 for (uint32_t i = 0; i < count; ++i) {
@@ -676,55 +592,6 @@ int32_t BuildOutputTensors(const ge::OpDescPtr &op_desc, const std::map<std::str
676 return 0;592 return 0;
677}593}
678 594 
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- 
728int32_t BuildNodeDefAttrs(const ge::Operator &op, aicpuops::NodeDef &node_def) {595int32_t BuildNodeDefAttrs(const ge::Operator &op, aicpuops::NodeDef &node_def) {
729 std::map<ge::AscendString, ge::AscendString> attrs;596 std::map<ge::AscendString, ge::AscendString> attrs;
730 if (op.GetAllAttrNamesAndTypes(attrs) != ge::GRAPH_SUCCESS) {597 if (op.GetAllAttrNamesAndTypes(attrs) != ge::GRAPH_SUCCESS) {
@@ -770,277 +637,6 @@ int32_t BuildNodeDef(const ge::Operator &op, const std::string &op_type_str,
770 return BuildNodeDefAttrs(op, node_def);637 return BuildNodeDefAttrs(op, node_def);
771}638}
772 639 
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- 
1044// 查找op_type对应的V2 binding。未命中返回nullptr表示走V1路径。640// 查找op_type对应的V2 binding。未命中返回nullptr表示走V1路径。
1045const V2ModuleBinding *LookupV2Binding(const std::string &op_type) {641const V2ModuleBinding *LookupV2Binding(const std::string &op_type) {
1046 auto iter = g_v2_op_index.find(op_type);642 auto iter = g_v2_op_index.find(op_type);
@@ -1054,14 +650,6 @@ const V2ModuleBinding *LookupV2Binding(const std::string &op_type) {
1054 return binding;650 return binding;
1055}651}
1056 652 
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- 
1065__attribute__((visibility("default"))) int32_t653__attribute__((visibility("default"))) int32_t
1066CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,654CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,
1067 std::map<std::string, ge::Tensor> outputs) {655 std::map<std::string, ge::Tensor> outputs) {
@@ -1109,302 +697,4 @@ CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string,
1109 AICPUE_LOGI("Finish cpu op[%s].", op_type.GetString());697 AICPUE_LOGI("Finish cpu op[%s].", op_type.GetString());
1110 return 0;698 return 0;
1111}699}
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-}
1410}700}
@@ -17,7 +17,6 @@
17#ifndef GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_17#ifndef GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
18#define GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_18#define GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
19 19 
20-#include <cstddef>
21#include <cstdint>20#include <cstdint>
22#include <map>21#include <map>
23#include <string>22#include <string>
@@ -28,23 +27,8 @@
28extern "C" {27extern "C" {
29__attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::HostCpuOp *(*create_fn)());28__attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::HostCpuOp *(*create_fn)());
30 29 
31-__attribute__((visibility("default"))) int32_t IsCpuConstantFoldingFusedOpSupported(const char *op_type);
32- 
33__attribute__((visibility("default"))) int32_t30__attribute__((visibility("default"))) int32_t
34CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,31CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,
35 std::map<std::string, ge::Tensor> outputs);32 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);
49}33}
50#endif // GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_34#endif // GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
@@ -28,7 +28,6 @@
28#include "aicpu_graph_optimizer/graph_optimizer_utils.h"28#include "aicpu_graph_optimizer/graph_optimizer_utils.h"
29#include "graph/anchor.h"29#include "graph/anchor.h"
30#include "graph/node.h"30#include "graph/node.h"
31-#include "framework/common/host_cpu_fusion_attr.h"
32 31 
33using namespace std;32using namespace std;
34using namespace ge;33using namespace ge;
@@ -280,24 +279,12 @@ static ge::Status FillOutputTensorOfAicpuNodeDef(const ge::OpDescPtr &op_desc_pt
280 aicpu_shape->set_data_format(static_cast<ge::Format>(output_desc.GetFormat()));279 aicpu_shape->set_data_format(static_cast<ge::Format>(output_desc.GetFormat()));
281 aicpu_shape->set_unknown_rank(is_unknow_shape);280 aicpu_shape->set_unknown_rank(is_unknow_shape);
282 output_tensor->set_tensor_type(static_cast<ge::DataType>(output_desc.GetDataType()));281 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- }
286 }282 }
287 return ge::SUCCESS;283 return ge::SUCCESS;
288}284}
289 285 
290ge::Status BuildAicpuNodeDef(const ge::OpDescPtr &op_desc_ptr, aicpuops::NodeDef &node_def) {286ge::Status BuildAicpuNodeDef(const ge::OpDescPtr &op_desc_ptr, aicpuops::NodeDef &node_def) {
291 std::string op_type = op_desc_ptr->GetType();287 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- }
301 node_def.set_op(op_type);288 node_def.set_op(op_type);
302 289 
303 bool is_unknow_shape = false;290 bool is_unknow_shape = false;
@@ -13,11 +13,9 @@
13#include <memory>13#include <memory>
14#include <vector>14#include <vector>
15#include "common/config/config_file.h"15#include "common/config/config_file.h"
16-#include "common/util/cpu_engine_util.h"
17#include "base/err_msg.h"16#include "base/err_msg.h"
18#include "common/util/util.h"17#include "common/util/util.h"
19#include "error_code/error_code.h"18#include "error_code/error_code.h"
20-#include "framework/common/host_cpu_fusion_attr.h"
21#include "ge/ge_api_types.h"19#include "ge/ge_api_types.h"
22#include "register/ops_kernel_builder_registry.h"20#include "register/ops_kernel_builder_registry.h"
23#include "graph/utils/op_desc_utils_ex.h"21#include "graph/utils/op_desc_utils_ex.h"
@@ -63,6 +61,7 @@ ge::Status HostCpuOpsKernelBuilder::CalcOpRunningParam(ge::Node &node) {
63 ge::OpDescUtilsEx::SetType(op_desc_ptr, *op_original_type);61 ge::OpDescUtilsEx::SetType(op_desc_ptr, *op_original_type);
64 op_type = *op_original_type;62 op_type = *op_original_type;
65 }63 }
64+ 
66 FACTORY_ENGINE::FactoryType host_engine_ptr = FACTORY_ENGINE::Produce(engine_name_);65 FACTORY_ENGINE::FactoryType host_engine_ptr = FACTORY_ENGINE::Produce(engine_name_);
67 AICPU_CHECK_NOTNULL_ERRCODE(host_engine_ptr, ErrorCode::INPUT_PARAM_NULL)66 AICPU_CHECK_NOTNULL_ERRCODE(host_engine_ptr, ErrorCode::INPUT_PARAM_NULL)
68 AicpuOpsKernelInfoStorePtr host_ops_kernel_info_store_ptr = host_engine_ptr->GetAicpuOpsKernelInfoStore();67 AicpuOpsKernelInfoStorePtr host_ops_kernel_info_store_ptr = host_engine_ptr->GetAicpuOpsKernelInfoStore();
@@ -78,17 +77,7 @@ ge::Status HostCpuOpsKernelBuilder::CalcOpRunningParam(ge::Node &node) {
78 AICPUE_LOGI("Node[%s] set attr optional_input_placeholder is [%s]", node.GetName().c_str(),77 AICPUE_LOGI("Node[%s] set attr optional_input_placeholder is [%s]", node.GetName().c_str(),
79 optional_input ? "true" : "false");78 optional_input ? "true" : "false");
80 }79 }
81- if ((op_type == ge::kFusedHostCpuOpType) && !ge::AttrUtils::HasAttr(op_desc_ptr, kCustomizedOpDef)) {80+ 
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- }
92 const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"];81 const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"];
93 AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER);82 AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER);
94 return kernel_builder->CalcOpRunningParam(node);83 return kernel_builder->CalcOpRunningParam(node);
@@ -112,10 +101,6 @@ ge::Status HostCpuOpsKernelBuilder::GenerateTask(const ge::Node &ge_node, ge::Ru
112 101 
113 const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"];102 const KernelBuilderPtr &kernel_builder = kernel_builder_map_["HOSTCPUBuilder"];
114 AICPU_CHECK_NOTNULL_ERRCODE(kernel_builder, ErrorCode::NONE_KERNEL_BUILDER);103 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- }
119 return kernel_builder->GenerateTask(ge_node, context, tasks);104 return kernel_builder->GenerateTask(ge_node, context, tasks);
120}105}
121 106 
@@ -34,6 +34,7 @@
34#include "graph/attribute_group/attr_group_shape_env.h"34#include "graph/attribute_group/attr_group_shape_env.h"
35#include "graph_metadef/common/ge_common/util.h"35#include "graph_metadef/common/ge_common/util.h"
36#include "common/ge_common/ge_types.h"36#include "common/ge_common/ge_types.h"
37+#include "graph/op_so_bin.h"
37 38 
38namespace ge {39namespace ge {
39namespace {40namespace {
@@ -50,6 +51,7 @@ const char_t *const kAnchorIndex = "anchorIndex";
50const char_t *const kTaskL2FusionInfo = "_task_L2FusionInfo";51const char_t *const kTaskL2FusionInfo = "_task_L2FusionInfo";
51const char_t *const kDataAnchorIndexForLxfusion = "_data_anchor_index_for_lxfusion";52const char_t *const kDataAnchorIndexForLxfusion = "_data_anchor_index_for_lxfusion";
52const char_t *const kEnableCvParallel = "_enable_cv_parallel";53const char_t *const kEnableCvParallel = "_enable_cv_parallel";
54+const char_t *const kSoBufferAttr = "bin_file_buffer";
53const char_t *const kVectorEngineName = "VectorEngine";55const char_t *const kVectorEngineName = "VectorEngine";
54const char_t *const kHostCpuEngineName = "DNN_VM_HOST_CPU";56const char_t *const kHostCpuEngineName = "DNN_VM_HOST_CPU";
55const std::string kStableRdfsSort = "3";57const std::string kStableRdfsSort = "3";
@@ -480,6 +482,20 @@ Status EnginePartitioner::InheritOriginalAttr(const ComputeGraphPtr &original_co
480 output_merged_compute_graph->SetExtAttr(ge::ATTR_NAME_DEVICE_INDEX_TO_LOGIC_DEVICE_ID, *device_mapping));482 output_merged_compute_graph->SetExtAttr(ge::ATTR_NAME_DEVICE_INDEX_TO_LOGIC_DEVICE_ID, *device_mapping));
481 }483 }
482 484 
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+ 
483 // AttrStore里面属性组没有被拷贝,并且没有提供CopyAllAttrStore方法,暂时先手动拷贝必须的499 // AttrStore里面属性组没有被拷贝,并且没有提供CopyAllAttrStore方法,暂时先手动拷贝必须的
484 auto origin_shape_env_attr = original_compute_graph->GetAttrsGroup<ShapeEnvAttr>();500 auto origin_shape_env_attr = original_compute_graph->GetAttrsGroup<ShapeEnvAttr>();
485 if (origin_shape_env_attr != nullptr) {501 if (origin_shape_env_attr != nullptr) {
@@ -12,11 +12,9 @@
12 12 
13#include <algorithm>13#include <algorithm>
14#include <cerrno>14#include <cerrno>
15-#include <cmath>
16#include <cstdlib>15#include <cstdlib>
17#include <iomanip>16#include <iomanip>
18#include <limits>17#include <limits>
19-#include <locale>
20#include <sstream>18#include <sstream>
21#include <unordered_map>19#include <unordered_map>
22#include <utility>20#include <utility>
@@ -36,6 +34,8 @@
36#include "graph/anchor.h"34#include "graph/anchor.h"
37#include "graph/ge_local_context.h"35#include "graph/ge_local_context.h"
38#include "graph_metadef/common/ge_common/util.h"36#include "graph_metadef/common/ge_common/util.h"
37+#include "exe_graph/lowering/bg_kernel_context_extend.h"
38+#include "exe_graph/lowering/buffer_pool.h"
39#include "graph/utils/attr_utils.h"39#include "graph/utils/attr_utils.h"
40 40 
41namespace ge {41namespace ge {
@@ -86,54 +86,6 @@ std::string EscapeCppString(const std::string &value) {
86 return os.str();86 return os.str();
87}87}
88 88 
89-std::string RangeExpression(const std::vector<std::pair<int64_t, int64_t>> &ranges) {
90- std::ostringstream os;
91- os << "std::vector<std::pair<int64_t, int64_t>>{";
92- for (size_t i = 0U; i < ranges.size(); ++i) {
93- if (i != 0U) {
94- os << ", ";
95- }
96- os << "{" << IntExpression(ranges[i].first) << ", " << IntExpression(ranges[i].second) << "}";
97- }
98- os << "}";
99- return os.str();
100-}
101- 
102-std::string TensorDescExpression(const GeTensorDesc &desc) {
103- std::ostringstream os;
104- os << "([]() { ge::TensorDesc desc(ge::Shape(std::vector<int64_t>{";
105- const auto dims = desc.GetShape().GetDims();
106- for (size_t i = 0U; i < dims.size(); ++i) {
107- if (i != 0U) {
108- os << ", ";
109- }
110- os << dims[i];
111- }
112- os << "}), static_cast<ge::Format>(" << static_cast<int32_t>(desc.GetFormat()) << "), static_cast<ge::DataType>("
113- << static_cast<int32_t>(desc.GetDataType()) << ")); ";
114- if (desc.IsOriginShapeInitialized()) {
115- os << "desc.SetOriginShape(ge::Shape(std::vector<int64_t>{";
116- const auto origin_dims = desc.GetOriginShape().GetDims();
117- for (size_t i = 0U; i < origin_dims.size(); ++i) {
118- if (i != 0U) {
119- os << ", ";
120- }
121- os << origin_dims[i];
122- }
123- os << "})); ";
124- }
125- os << "desc.SetOriginFormat(static_cast<ge::Format>(" << static_cast<int32_t>(desc.GetOriginFormat())
126- << ")); desc.SetName(std::string(\"" << EscapeCppString(desc.GetName()) << "\", " << desc.GetName().size()
127- << "U)); desc.SetExpandDimsRule(ge::AscendString(\"" << EscapeCppString(desc.GetExpandDimsRule())
128- << "\")); desc.SetPlacement(static_cast<ge::Placement>(" << static_cast<int32_t>(desc.GetPlacement()) << ")); ";
129- std::vector<std::pair<int64_t, int64_t>> ranges;
130- if ((desc.GetShapeRange(ranges) == GRAPH_SUCCESS) && !ranges.empty()) {
131- os << "(void)desc.SetShapeRange(" << RangeExpression(ranges) << "); ";
132- }
133- os << "return desc; }())";
134- return os.str();
135-}
136- 
137Status GetTensorSize(const GeTensorDesc &desc, size_t &size) {89Status GetTensorSize(const GeTensorDesc &desc, size_t &size) {
138 const auto &shape = desc.GetShape();90 const auto &shape = desc.GetShape();
139 if (shape.IsUnknownShape()) {91 if (shape.IsUnknownShape()) {
@@ -158,43 +110,6 @@ std::string IntExpression(const int64_t value) {
158 return std::to_string(value) + "LL";110 return std::to_string(value) + "LL";
159}111}
160 112 
161-std::string IntVectorExpression(const std::vector<int64_t> &values) {
162- std::ostringstream os;
163- os << "{";
164- for (size_t i = 0U; i < values.size(); ++i) {
165- if (i != 0U) {
166- os << ", ";
167- }
168- os << IntExpression(values[i]);
169- }
170- os << "}";
171- return os.str();
172-}
173- 
174-std::string FloatExpression(const float value) {
175- std::ostringstream os;
176- os.imbue(std::locale::classic());
177- os << std::setprecision(std::numeric_limits<float>::max_digits10) << value;
178- std::string expression = os.str();
179- if (expression.find_first_of(".eE") == std::string::npos) {
180- expression += ".0";
181- }
182- return expression + "F";
183-}
184- 
185-std::string FloatVectorExpression(const std::vector<float> &values) {
186- std::ostringstream os;
187- os << "{";
188- for (size_t i = 0U; i < values.size(); ++i) {
189- if (i != 0U) {
190- os << ", ";
191- }
192- os << FloatExpression(values[i]);
193- }
194- os << "}";
195- return os.str();
196-}
197- 
198#if defined(__linux__)113#if defined(__linux__)
199constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U;114constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U;
200 115 
@@ -338,12 +253,16 @@ bool HasHeader(const std::vector<std::string> &include_paths, const std::string
338}253}
339 254 
340bool CheckRequiredHeaders(const std::vector<std::string> &include_paths) {255bool CheckRequiredHeaders(const std::vector<std::string> &include_paths) {
341- static const std::vector<std::string> kRequiredHeaders = {"aicpu/cpu_kernels/cpu_kernel.h",256+ // Keep this list aligned with the headers emitted below. The generated SO only
342- "aicpu/cpu_kernels/cpu_kernel_register.h",257+ // uses the public HostCpuExecuteOp/KernelContext ABI; requiring the legacy
343- "graph/operator.h", "graph/tensor.h"};258+ // CpuKernel registration headers made JIT depend on headers it never included.
259+ static const std::vector<std::string> kRequiredHeaders = {
260+ "exe_graph/runtime/compute_node_info.h", "exe_graph/runtime/gert_tensor_data.h",
261+ "exe_graph/runtime/kernel_context.h", "exe_graph/runtime/kernel_run_context.h",
262+ "exe_graph/runtime/runtime_tensor.h", "graph/custom_op.h"};
344 for (const auto &header : kRequiredHeaders) {263 for (const auto &header : kRequiredHeaders) {
345 if (!HasHeader(include_paths, header)) {264 if (!HasHeader(include_paths, header)) {
346- GELOGE(UNSUPPORTED, "HostCPU fusion JIT header %s was not found, include_paths=%s.", header.c_str(),265+ GELOGW("HostCPU fusion JIT header %s was not found, include_paths=%s.", header.c_str(),
347 JoinPaths(include_paths).c_str());266 JoinPaths(include_paths).c_str());
348 return false;267 return false;
349 }268 }
@@ -433,674 +352,483 @@ Status HostCpuFusionCodegen::Generate(const HostCpuFusionRegion &region, HostCpu
433 region.chain_id.c_str(), region.nodes.size(), region.external_inputs.size(), region.external_outputs.size());352 region.chain_id.c_str(), region.nodes.size(), region.external_inputs.size(), region.external_outputs.size());
434 return PARAM_INVALID;353 return PARAM_INVALID;
435 }354 }
436- 
437- /** chain_id还必须能作为 C++ 标识符的一部分:
438- * - 不能以数字开头;
439- * - 只能包含字母、数字和下划线;
440- * - 最终注册名不能超过 160 字节。
441- */
442 if (((region.chain_id.front() >= '0') && (region.chain_id.front() <= '9')) ||355 if (((region.chain_id.front() >= '0') && (region.chain_id.front() <= '9')) ||
443 !std::all_of(region.chain_id.cbegin(), region.chain_id.cend(),356 !std::all_of(region.chain_id.cbegin(), region.chain_id.cend(),
444 [](const unsigned char ch) { return IsAsciiAlphaNumeric(ch) || (ch == '_'); })) {357 [](const unsigned char ch) { return IsAsciiAlphaNumeric(ch) || (ch == '_'); })) {
445 GELOGE(PARAM_INVALID, "Invalid HostCPU fusion chain id[%s].", region.chain_id.c_str());358 GELOGE(PARAM_INVALID, "Invalid HostCPU fusion chain id[%s].", region.chain_id.c_str());
446 return PARAM_INVALID;359 return PARAM_INVALID;
447 }360 }
361+ 
448 const std::string register_name = std::string(kFusedHostCpuOpType) + "_" + region.chain_id;362 const std::string register_name = std::string(kFusedHostCpuOpType) + "_" + region.chain_id;
449 if (register_name.size() > kMaxRegisterNameSize) {363 if (register_name.size() > kMaxRegisterNameSize) {
450 GELOGE(PARAM_INVALID, "HostCPU fusion register name is too long: chain[%s], register_name[%s], size[%zu].",364 GELOGE(PARAM_INVALID, "HostCPU fusion register name is too long: chain[%s], register_name[%s], size[%zu].",
451 region.chain_id.c_str(), register_name.c_str(), register_name.size());365 region.chain_id.c_str(), register_name.c_str(), register_name.size());
452 return PARAM_INVALID;366 return PARAM_INVALID;
453 }367 }
454- GELOGD("Generate HostCPU fusion orchestration: chain=%s, nodes=%zu, inputs=%zu, outputs=%zu.",
455- region.chain_id.c_str(), region.nodes.size(), region.external_inputs.size(), region.external_outputs.size());
456 368 
457- // 校验节点和 anchor 唯一性,并将图对象映射为稳定的生成代码下标。
458 std::unordered_map<const Node *, size_t> node_indexes;369 std::unordered_map<const Node *, size_t> node_indexes;
459 for (size_t i = 0U; i < region.nodes.size(); ++i) {370 for (size_t i = 0U; i < region.nodes.size(); ++i) {
460- if ((region.nodes[i] == nullptr) || (region.nodes[i]->GetOpDesc() == nullptr)) {371+ if ((region.nodes[i] == nullptr) || (region.nodes[i]->GetOpDesc() == nullptr) ||
461- GELOGE(PARAM_INVALID, "Invalid HostCPU fusion node: chain[%s], node_index[%zu], node_null[%d], op_desc_null[%d].",372+ !node_indexes.emplace(region.nodes[i].get(), i).second) {
462- region.chain_id.c_str(), i, static_cast<int32_t>(region.nodes[i] == nullptr),373+ GELOGE(PARAM_INVALID, "Invalid or duplicate HostCPU fusion node: chain[%s], node_index[%zu].",
463- static_cast<int32_t>((region.nodes[i] != nullptr) && (region.nodes[i]->GetOpDesc() == nullptr)));374+ region.chain_id.c_str(), i);
464- return PARAM_INVALID;
465- }
466- if (!node_indexes.emplace(region.nodes[i].get(), i).second) {
467- GELOGE(PARAM_INVALID, "Duplicate HostCPU fusion node: chain[%s], node_index[%zu], node[%s].",
468- region.chain_id.c_str(), i, region.nodes[i]->GetNamePtr());
469 return PARAM_INVALID;375 return PARAM_INVALID;
470 }376 }
471 }377 }
378+ 
472 std::unordered_map<const OutDataAnchor *, size_t> input_indexes;379 std::unordered_map<const OutDataAnchor *, size_t> input_indexes;
473 for (size_t i = 0U; i < region.external_inputs.size(); ++i) {380 for (size_t i = 0U; i < region.external_inputs.size(); ++i) {
474- if ((region.external_inputs[i] == nullptr) ||381+ const auto &anchor = region.external_inputs[i];
475- (node_indexes.count(region.external_inputs[i]->GetOwnerNode().get()) > 0U)) {382+ if ((anchor == nullptr) || (node_indexes.count(anchor->GetOwnerNode().get()) > 0U) ||
476- GELOGE(PARAM_INVALID, "Invalid HostCPU fusion external input: chain[%s], input_index[%zu], anchor_null[%d].",383+ !input_indexes.emplace(anchor.get(), i).second) {
477- region.chain_id.c_str(), i, static_cast<int32_t>(region.external_inputs[i] == nullptr));384+ GELOGE(PARAM_INVALID, "Invalid HostCPU fusion external input: chain[%s], input_index[%zu].",
478- return PARAM_INVALID;
479- }
480- if (!input_indexes.emplace(region.external_inputs[i].get(), i).second) {
481- GELOGE(PARAM_INVALID, "Duplicate HostCPU fusion external input: chain[%s], input_index[%zu].",
482 region.chain_id.c_str(), i);385 region.chain_id.c_str(), i);
483 return PARAM_INVALID;386 return PARAM_INVALID;
484 }387 }
485 }388 }
389+ 
486 std::unordered_map<const OutDataAnchor *, size_t> output_indexes;390 std::unordered_map<const OutDataAnchor *, size_t> output_indexes;
487 for (size_t i = 0U; i < region.external_outputs.size(); ++i) {391 for (size_t i = 0U; i < region.external_outputs.size(); ++i) {
488- if ((region.external_outputs[i].source == nullptr) ||392+ const auto &anchor = region.external_outputs[i].source;
489- (node_indexes.count(region.external_outputs[i].source->GetOwnerNode().get()) == 0U)) {393+ if ((anchor == nullptr) || (node_indexes.count(anchor->GetOwnerNode().get()) == 0U) ||
490- GELOGE(PARAM_INVALID, "Invalid HostCPU fusion external output: chain[%s], output_index[%zu], source_null[%d].",394+ !output_indexes.emplace(anchor.get(), i).second) {
491- region.chain_id.c_str(), i, static_cast<int32_t>(region.external_outputs[i].source == nullptr));395+ GELOGE(PARAM_INVALID, "Invalid HostCPU fusion external output: chain[%s], output_index[%zu].",
492- return PARAM_INVALID;
493- }
494- if (!output_indexes.emplace(region.external_outputs[i].source.get(), i).second) {
495- GELOGE(PARAM_INVALID, "Duplicate HostCPU fusion external output: chain[%s], output_index[%zu].",
496 region.chain_id.c_str(), i);396 region.chain_id.c_str(), i);
497 return PARAM_INVALID;397 return PARAM_INVALID;
498 }398 }
499 }399 }
500 400 
401+ const auto shape_expression = [](const GeShape &shape) {
402+ std::ostringstream os;
403+ os << "gert::StorageShape({";
404+ const auto dims = shape.GetDims();
405+ for (size_t i = 0U; i < dims.size(); ++i) {
406+ if (i != 0U) {
407+ os << ", ";
408+ }
409+ os << IntExpression(dims[i]);
410+ }
411+ os << "}, {";
412+ for (size_t i = 0U; i < dims.size(); ++i) {
413+ if (i != 0U) {
414+ os << ", ";
415+ }
416+ os << IntExpression(dims[i]);
417+ }
418+ os << "})";
419+ return os.str();
420+ };
421+ const auto format_expression = [](const GeTensorDesc &desc) {
422+ std::ostringstream os;
423+ os << "gert::StorageFormat(static_cast<ge::Format>(" << static_cast<int32_t>(desc.GetOriginFormat())
424+ << "), static_cast<ge::Format>(" << static_cast<int32_t>(desc.GetFormat()) << "), gert::ExpandDimsType())";
425+ return os.str();
426+ };
427+ const auto emit_bytes = [](const uint8_t *data, const size_t size) {
428+ std::ostringstream os;
429+ os << "{{";
430+ for (size_t i = 0U; i < size; ++i) {
431+ if (i != 0U) {
432+ os << ", ";
433+ }
434+ os << static_cast<uint32_t>(data[i]) << "U";
435+ }
436+ os << "}}";
437+ return os.str();
438+ };
439+ 
440+ // The generated executor may contain many nodes with the same op type (for example, a
441+ // long Pack chain). Keep one runtime lookup slot per distinct type so the hot path does
442+ // not repeatedly call the HostCPU registry finder.
443+ std::unordered_map<std::string, size_t> kernel_type_indexes;
444+ std::vector<std::string> kernel_types;
445+ kernel_types.reserve(region.nodes.size());
446+ for (const auto &node : region.nodes) {
447+ const std::string type = node->GetType();
448+ if (kernel_type_indexes.find(type) == kernel_type_indexes.end()) {
449+ const size_t type_index = kernel_types.size();
450+ kernel_type_indexes.emplace(type, type_index);
451+ kernel_types.emplace_back(type);
452+ }
453+ }
454+ 
501 std::ostringstream code;455 std::ostringstream code;
502- code << "#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <limits>\n"456+ code << "#include <algorithm>\n#include <array>\n#include <atomic>\n#include <cstddef>\n#include <cstdint>\n"
503- << "#include <memory>\n#include <new>\n#include <string>\n#include <utility>\n#include <vector>\n"457+ << "#include <cstring>\n#include <dlfcn.h>\n#include <memory>\n#include <new>\n"
504- << "#include \"aicpu/cpu_kernels/cpu_kernel.h\"\n"458+ << "#include <string>\n#include <vector>\n"
505- << "#include \"aicpu/cpu_kernels/cpu_kernel_register.h\"\n"459+ << "#include \"exe_graph/runtime/compute_node_info.h\"\n"
506- << "#include \"graph/operator.h\"\n"460+ << "#include \"exe_graph/runtime/gert_tensor_data.h\"\n"
507- << "#include \"graph/tensor.h\"\n\n"461+ << "#include \"exe_graph/runtime/kernel_context.h\"\n"
508- << "extern \"C\" void *CreateCpuConstantFoldingFusedChainPlan(const void *, size_t, size_t, size_t);\n"462+ << "#include \"exe_graph/runtime/kernel_run_context.h\"\n"
509- << "extern \"C\" int32_t RunCpuConstantFoldingFusedChainPlan(void *, uint32_t);\n"463+ << "#include \"exe_graph/runtime/runtime_tensor.h\"\n"
510- << "extern \"C\" int32_t RunCpuConstantFoldingFusedChainPlanBindings(void *, const void *, uint32_t);\n"464+ << "#include \"graph/custom_op.h\"\n\n"
511- << "extern \"C\" void DestroyCpuConstantFoldingFusedChainPlan(void *);\n\n"
512 << "namespace {\n"465 << "namespace {\n"
513- << "struct FusedHostCpuNodePlanDesc {\n"466+ << "using HostKernelFunc = ge::graphStatus (*)(gert::KernelContext *);\n"
514- << " const ge::Operator *op;\n"467+ << "using HostKernelFinder = HostKernelFunc (*)(std::string);\n\n"
515- << " const ge::Tensor *const *inputs;\n"468+ << "template <size_t InputNum, size_t OutputNum>\n"
516- << " size_t input_num;\n"469+ << "class LocalKernelContext final {\n public:\n"
517- << " ge::Tensor *const *outputs;\n"470+ << " static constexpr size_t kValueNum = InputNum * 2U + 1U + OutputNum * 2U;\n"
518- << " size_t output_num;\n"471+ << " static constexpr size_t kStorageSize = sizeof(KernelRunContext) +\n"
519- << " const int32_t *input_binding_indices;\n"472+ << " (kValueNum - 1U) * sizeof(AsyncAnyValue *);\n"
520- << " const int32_t *output_binding_indices;\n"473+ << " LocalKernelContext(const gert::ComputeNodeInfo *node_info,\n"
521- << "};\n\n"474+ << " const std::array<const gert::Tensor *, InputNum> &inputs,\n"
522- << "enum FusedHostCpuBindingFlag : uint32_t {\n"475+ << " const std::array<gert::Tensor *, OutputNum> &outputs, HostKernelFunc func)\n"
523- << " kFusedHostCpuShapeChanged = 1U,\n"476+ << " : input_tensor_data_{}, output_tensor_data_{}, values_{}, storage_{} {\n"
524- << " kFusedHostCpuDataChanged = 2U\n"477+ << " auto *run = reinterpret_cast<KernelRunContext *>(storage_.data());\n"
525- << "};\n\n"478+ << " constexpr size_t input_num = InputNum;\n"
526- << "struct FusedHostCpuTensorBinding {\n"479+ << " constexpr size_t output_num = OutputNum;\n"
527- << " const int64_t *dims;\n"480+ << " run->input_size = input_num * 2U + 1U;\n"
528- << " uint8_t *data;\n"481+ << " run->output_size = output_num * 2U;\n"
529- << " size_t dim_num;\n"482+ << " run->compute_node_info = node_info;\n"
530- << " size_t data_size;\n"483+ << " run->kernel_extend_info = nullptr;\n"
531- << " uint32_t flags;\n"484+ << " for (size_t i = 0U; i < input_num; ++i) {\n"
532- << "};\n\n"485+ << " const auto *tensor = inputs[i];\n"
533- << "class FusedHostCpuChainPlanGuard {\n public:\n"486+ << " const auto placement = (tensor->GetPlacement() == gert::kFollowing) ? gert::kOnHost :\n"
534- << " ~FusedHostCpuChainPlanGuard() { DestroyCpuConstantFoldingFusedChainPlan(plan_); }\n"487+ << " tensor->GetPlacement();\n"
535- << " void *Get() const { return plan_; }\n"488+ << " input_tensor_data_[i].MutableTensorData() =\n"
536- << " void Reset(void *plan) {\n"489+ << " gert::TensorData(const_cast<void *>(tensor->GetAddr()), nullptr, tensor->GetSize(), placement);\n"
537- << " if (plan_ != plan) { DestroyCpuConstantFoldingFusedChainPlan(plan_); plan_ = plan; }\n"
538- << " }\n"
539- << " private:\n void *plan_ = nullptr;\n};\n\n"
540- << "struct FusedHostCpuTensorState {\n"
541- << " ge::DataType data_type = ge::DT_UNDEFINED;\n"
542- << " ge::Format format = ge::FORMAT_RESERVED;\n"
543- << " const void *data = nullptr;\n"
544- << " size_t data_size = 0U;\n"
545- << " std::vector<int64_t> dims;\n"
546- << " bool initialized = false;\n"
547- << "};\n\n"
548- << "bool HasSameFusedHostCpuShape(const aicpu::TensorShape &shape,\n"
549- << " const FusedHostCpuTensorState &state) {\n"
550- << " const int32_t dim_num = shape.GetDims();\n"
551- << " if ((dim_num < 0) || (state.dims.size() != static_cast<size_t>(dim_num))) { return false; }\n"
552- << " for (int32_t i = 0; i < dim_num; ++i) {\n"
553- << " if (state.dims[static_cast<size_t>(i)] != shape.GetDimSize(i)) { return false; }\n"
554- << " }\n"
555- << " return true;\n"
556- << "}\n\n"
557- << "bool BuildFusedHostCpuTensor(aicpu::Tensor *source, ge::Tensor &target,\n"
558- << " FusedHostCpuTensorState &state, bool &changed) {\n"
559- << " if (source == nullptr) { return false; }\n"
560- << " const auto shape = source->GetTensorShape();\n"
561- << " if (shape == nullptr) { return false; }\n"
562- << " const int32_t dim_num = shape->GetDims();\n"
563- << " if (dim_num < 0) { return false; }\n"
564- << " const auto data_type = static_cast<ge::DataType>(source->GetDataType());\n"
565- << " const auto format = static_cast<ge::Format>(shape->GetFormat());\n"
566- << " const uint64_t data_size = source->GetDataSize();\n"
567- << " if ((data_size > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) ||\n"
568- << " ((data_size != 0U) && (source->GetData() == nullptr))) { return false; }\n"
569- << " const void *data = source->GetData();\n"
570- << " const bool rebuild = !state.initialized || (state.data_type != data_type) ||\n"
571- << " (state.format != format) || !HasSameFusedHostCpuShape(*shape, state) ||\n"
572- << " ((data_size == 0U) && (state.data_size != 0U));\n"
573- << " changed = rebuild || (state.data != data) || (state.data_size != data_size);\n"
574- << " if (rebuild) {\n"
575- << " state.dims.resize(static_cast<size_t>(dim_num));\n"
576- << " for (int32_t i = 0; i < dim_num; ++i) {\n"
577- << " state.dims[static_cast<size_t>(i)] = shape->GetDimSize(i);\n"
578 << " }\n"490 << " }\n"
579- << " ge::TensorDesc desc(ge::Shape(state.dims), format, data_type);\n"491+ << " for (size_t i = 0U; i < output_num; ++i) {\n"
580- << " desc.SetOriginShape(ge::Shape(state.dims));\n"492+ << " auto *tensor = outputs[i];\n"
581- << " desc.SetOriginFormat(format);\n"493+ << " const auto placement = (tensor->GetPlacement() == gert::kFollowing) ? gert::kOnHost :\n"
582- << " desc.SetPlacement(ge::kPlacementHost);\n"494+ << " tensor->GetPlacement();\n"
583- << " target = ge::Tensor(desc);\n"495+ << " output_tensor_data_[i].MutableTensorData() =\n"
584- << " state.data_type = data_type;\n"496+ << " gert::TensorData(tensor->GetAddr(), nullptr, tensor->GetSize(), placement);\n"
585- << " state.format = format;\n"497+ << " }\n"
498+ << " for (size_t i = 0U; i < input_num; ++i) {\n"
499+ << " run->values[i] = &values_[i];\n"
500+ << " values_[i].data.pointer = const_cast<gert::StorageShape *>(&inputs[i]->GetShape());\n"
501+ << " values_[i].deleter = nullptr;\n"
502+ << " run->values[input_num + i] = &values_[input_num + i];\n"
503+ << " values_[input_num + i].data.pointer = &input_tensor_data_[i];\n"
504+ << " values_[input_num + i].deleter = nullptr;\n"
505+ << " }\n"
506+ << " // Keep the same trailing function-pointer slot as AicpuHostExecFunc.\n"
507+ << " run->values[input_num * 2U] = &values_[input_num * 2U];\n"
508+ << " (void)std::memcpy(values_[input_num * 2U].data.inplace, &func, sizeof(func));\n"
509+ << " values_[input_num * 2U].deleter = nullptr;\n"
510+ << " const size_t output_start = input_num * 2U + 1U;\n"
511+ << " for (size_t i = 0U; i < output_num; ++i) {\n"
512+ << " run->values[output_start + i] = &values_[output_start + i];\n"
513+ << " values_[output_start + i].data.pointer = &outputs[i]->GetShape();\n"
514+ << " values_[output_start + i].deleter = nullptr;\n"
515+ << " run->values[output_start + output_num + i] = &values_[output_start + output_num + i];\n"
516+ << " values_[output_start + output_num + i].data.pointer = &output_tensor_data_[i];\n"
517+ << " values_[output_start + output_num + i].deleter = nullptr;\n"
518+ << " }\n"
519+ << " run->output_start = run->values + run->input_size;\n"
586 << " }\n"520 << " }\n"
587- << " if ((data_size != 0U) && changed &&\n"521+ << " gert::KernelContext *Get() { return reinterpret_cast<gert::KernelContext *>(storage_.data()); }\n"
588- << " (target.SetData(reinterpret_cast<uint8_t *>(source->GetData()),\n"522+ << " private:\n"
589- << " static_cast<size_t>(data_size), [](uint8_t *) {}) != ge::GRAPH_SUCCESS)) {\n"523+ << " alignas(gert::GertTensorData) std::array<gert::GertTensorData, InputNum> input_tensor_data_;\n"
590- << " return false;\n"524+ << " alignas(gert::GertTensorData) std::array<gert::GertTensorData, OutputNum> output_tensor_data_;\n"
525+ << " std::array<AsyncAnyValue, kValueNum> values_;\n"
526+ << " alignas(KernelRunContext) std::array<uint8_t, kStorageSize> storage_;\n"
527+ << "};\n\n"
528+ << "class HostKernelCache final {\n public:\n"
529+ << " HostKernelCache() : finder_(nullptr) {}\n"
530+ << " HostKernelFinder GetFinder() {\n"
531+ << " HostKernelFinder finder = finder_.load(std::memory_order_acquire);\n"
532+ << " if (finder != nullptr) { return finder; }\n"
533+ << " const auto candidate = reinterpret_cast<HostKernelFinder>(dlsym(RTLD_DEFAULT, \"AicpuHostFindFunc\"));\n"
534+ << " if (candidate == nullptr) { return nullptr; }\n"
535+ << " HostKernelFinder expected = nullptr;\n"
536+ << " if (!finder_.compare_exchange_strong(expected, candidate, std::memory_order_release,\n"
537+ << " std::memory_order_acquire)) {\n"
538+ << " return expected;\n"
539+ << " }\n"
540+ << " return candidate;\n"
591 << " }\n"541 << " }\n"
592- << " state.data = data;\n"542+ << " HostKernelFunc GetKernel(const HostKernelFinder finder,\n"
593- << " state.data_size = static_cast<size_t>(data_size);\n"543+ << " std::atomic<HostKernelFunc> &slot, const char *type) {\n"
594- << " state.initialized = true;\n"544+ << " HostKernelFunc kernel = slot.load(std::memory_order_acquire);\n"
595- << " return true;\n"545+ << " if (kernel != nullptr) { return kernel; }\n"
596- << "}\n\n"546+ << " if (finder == nullptr) { return nullptr; }\n"
597- << "bool BuildFusedHostCpuRuntimeTensor(const FusedHostCpuTensorBinding &binding,\n"547+ << " const auto candidate = finder(std::string(type));\n"
598- << " ge::TensorDesc desc, ge::Tensor &target) {\n"548+ << " if (candidate == nullptr) { return nullptr; }\n"
599- << " if (((binding.dim_num != 0U) && (binding.dims == nullptr)) ||\n"549+ << " HostKernelFunc expected = nullptr;\n"
600- << " ((binding.data_size != 0U) && (binding.data == nullptr))) { return false; }\n"550+ << " if (!slot.compare_exchange_strong(expected, candidate, std::memory_order_release,\n"
601- << " std::vector<int64_t> dims(binding.dim_num);\n"551+ << " std::memory_order_acquire)) {\n"
602- << " for (size_t i = 0U; i < binding.dim_num; ++i) { dims[i] = binding.dims[i]; }\n"552+ << " return expected;\n"
603- << " desc.SetShape(ge::Shape(dims));\n"553+ << " }\n"
604- << " desc.SetOriginShape(ge::Shape(dims));\n"554+ << " return candidate;\n"
605- << " desc.SetPlacement(ge::kPlacementHost);\n"555+ << " }\n"
606- << " target = ge::Tensor(desc);\n"556+ << " private:\n"
607- << " return (binding.data_size == 0U) ||\n"557+ << " std::atomic<HostKernelFinder> finder_;\n"
608- << " (target.ResetData(binding.data, binding.data_size, [](uint8_t *) {}) == ge::GRAPH_SUCCESS);\n"558+ << "};\n\n"
559+ << "HostKernelCache &GetHostKernelCache() {\n"
560+ << " static HostKernelCache cache;\n"
561+ << " return cache;\n"
609 << "}\n"562 << "}\n"
610- << "} // namespace\n\n"563+ << "HostKernelFinder GetHostKernelFinder() {\n"
611- << "namespace ge {\nclass FusedHostCpuNodeOperator_" << region.chain_id << " : public Operator {\n public:\n"564+ << " return GetHostKernelCache().GetFinder();\n"
612- << " FusedHostCpuNodeOperator_" << region.chain_id565+ << "}\n"
613- << "(const char *name, const char *type, const std::vector<std::string> &input_names,\n"566+ << "HostKernelFunc GetCachedHostKernel(const HostKernelFinder finder,\n"
614- << " const std::vector<std::string> &output_names)\n"567+ << " std::atomic<HostKernelFunc> &slot, const char *type) {\n"
615- << " : Operator(name, type) {\n"568+ << " return GetHostKernelCache().GetKernel(finder, slot, type);\n"
616- << " for (const auto &input_name : input_names) { InputRegister(input_name.c_str()); }\n"569+ << "}\n";
617- << " for (const auto &output_name : output_names) { OutputRegister(output_name.c_str()); }\n"570+ 
618- << " }\n};\n\n"571+ for (size_t type_index = 0U; type_index < kernel_types.size(); ++type_index) {
619- << "class FusedHostCpuOrchestration_" << region.chain_id << " {\n public:\n"572+ code << "HostKernelFunc GetHostKernel_" << type_index << "(const HostKernelFinder finder) {\n"
620- << " graphStatus Initialize() {\n"573+ << " static std::atomic<HostKernelFunc> kernel(nullptr);\n"
621- << " if (chain_plan_.Get() != nullptr) { return GRAPH_SUCCESS; }\n"574+ << " return GetCachedHostKernel(finder, kernel, \"" << EscapeString(kernel_types[type_index]) << "\");\n"
622- << " // Build immutable CpuKernel contexts after real runtime tensors are available.\n"575+ << "}\n";
623- << " if (!runtime_bound_) {\n"576+ }
624- << " static uint8_t placeholder_data = 0U;\n";577+ 
578+ code << "} // namespace\n\n"
579+ << "namespace ge {\n"
580+ << "class FusedHostCpuCustomOp_" << region.chain_id
581+ << " final : public HostCpuExecuteOp, public PortableOp {\n public:\n"
582+ << " graphStatus Serialize(std::vector<uint8_t> &buffer) override {\n"
583+ << " buffer = {0U};\n"
584+ << " return GRAPH_SUCCESS;\n"
585+ << " }\n"
586+ << " graphStatus Deserialize(const std::vector<uint8_t> &buffer) override {\n"
587+ << " (void)buffer;\n"
588+ << " return GRAPH_SUCCESS;\n"
589+ << " }\n"
590+ << " graphStatus Execute(gert::HostCpuOpExecutionContext *ctx) override {\n"
591+ << " if (ctx == nullptr) { return GRAPH_FAILED; }\n"
592+ << " HostKernelFinder finder = GetHostKernelFinder();\n"
593+ << " if (finder == nullptr) { return GRAPH_FAILED; }\n";
594+ 
595+ for (size_t type_index = 0U; type_index < kernel_types.size(); ++type_index) {
596+ code << " HostKernelFunc cached_kernel_" << type_index << " = nullptr;\n";
597+ }
625 598 
626 for (size_t i = 0U; i < region.external_inputs.size(); ++i) {599 for (size_t i = 0U; i < region.external_inputs.size(); ++i) {
627- const auto anchor = region.external_inputs[i];600+ code << " const gert::Tensor *external_input_" << i << " = ctx->GetInputTensor(" << i << "U);\n"
628- const auto owner = (anchor == nullptr) ? nullptr : anchor->GetOwnerNode();601+ << " if (external_input_" << i << " == nullptr) { return GRAPH_FAILED; }\n";
629- const auto op_desc = (owner == nullptr) ? nullptr : owner->GetOpDesc();
630- if ((op_desc == nullptr) || (anchor->GetIdx() < 0) ||
631- (static_cast<size_t>(anchor->GetIdx()) >= op_desc->GetOutputsSize())) {
632- GELOGE(PARAM_INVALID,
633- "Invalid HostCPU fusion input anchor while generating: chain[%s], input_index[%zu], "
634- "anchor_null[%d], owner_null[%d].",
635- region.chain_id.c_str(), i, static_cast<int32_t>(anchor == nullptr),
636- static_cast<int32_t>(owner == nullptr));
637- return PARAM_INVALID;
638- }
639- code << " inputs_[" << i << "U] = Tensor("
640- << TensorDescExpression(op_desc->GetOutputDesc(static_cast<size_t>(anchor->GetIdx()))) << ");\n"
641- << " if (inputs_[" << i
642- << "U].ResetData(&placeholder_data, sizeof(placeholder_data), [](uint8_t *) {}) != GRAPH_SUCCESS) "
643- << "{ return GRAPH_FAILED; }\n";
644 }602 }
645- for (size_t i = 0U; i < region.external_outputs.size(); ++i) {
646- const auto anchor = region.external_outputs[i].source;
647- const auto owner = (anchor == nullptr) ? nullptr : anchor->GetOwnerNode();
648- const auto op_desc = (owner == nullptr) ? nullptr : owner->GetOpDesc();
649- if ((op_desc == nullptr) || (anchor->GetIdx() < 0) ||
650- (static_cast<size_t>(anchor->GetIdx()) >= op_desc->GetOutputsSize())) {
651- GELOGE(PARAM_INVALID,
652- "Invalid HostCPU fusion output anchor while generating: chain[%s], output_index[%zu], "
653- "anchor_null[%d], owner_null[%d].",
654- region.chain_id.c_str(), i, static_cast<int32_t>(anchor == nullptr),
655- static_cast<int32_t>(owner == nullptr));
656- return PARAM_INVALID;
657- }
658- code << " outputs_[" << i << "U] = Tensor("
659- << TensorDescExpression(op_desc->GetOutputDesc(static_cast<size_t>(anchor->GetIdx()))) << ");\n"
660- << " if (outputs_[" << i
661- << "U].ResetData(&placeholder_data, sizeof(placeholder_data), [](uint8_t *) {}) != GRAPH_SUCCESS) "
662- << "{ return GRAPH_FAILED; }\n";
663- }
664- code << " }\n";
665 603 
666- size_t internal_tensor_count = 0U;604+ for (size_t i = 0U; i < region.external_outputs.size(); ++i) {
605+ const auto &anchor = region.external_outputs[i].source;
606+ const auto &desc = anchor->GetOwnerNode()->GetOpDesc()->GetOutputDesc(static_cast<uint32_t>(anchor->GetIdx()));
607+ if (desc.GetShape().IsUnknownShape()) {
608+ GELOGW("HostCPU fusion external output shape is unknown: chain[%s], output[%zu].", region.chain_id.c_str(), i);
609+ return UNSUPPORTED;
610+ }
611+ code << " gert::Tensor *external_output_" << i << " = ctx->MallocOutputTensor(" << i << "U, "
612+ << shape_expression(desc.GetShape()) << ", " << format_expression(desc) << ", static_cast<ge::DataType>("
613+ << static_cast<int32_t>(desc.GetDataType()) << "));\n"
614+ << " if (external_output_" << i << " == nullptr) { return GRAPH_FAILED; }\n";
615+ }
616+ 
617+ struct InternalBuffer {
618+ OutDataAnchorPtr anchor;
619+ size_t offset;
620+ };
621+ std::vector<InternalBuffer> internal_buffers;
622+ std::unordered_map<const OutDataAnchor *, size_t> internal_indexes;
623+ size_t internal_storage_size = 0U;
624+ constexpr size_t kInternalBufferAlignment = alignof(std::max_align_t);
667 for (const auto &node : region.nodes) {625 for (const auto &node : region.nodes) {
668 for (const auto &anchor : node->GetAllOutDataAnchors()) {626 for (const auto &anchor : node->GetAllOutDataAnchors()) {
669- if ((anchor != nullptr) && (output_indexes.count(anchor.get()) == 0U)) {627+ if ((anchor == nullptr) || (output_indexes.count(anchor.get()) > 0U)) {
670- ++internal_tensor_count;628+ continue;
671 }629 }
630+ size_t tensor_size = 0U;
631+ const auto &desc = node->GetOpDesc()->GetOutputDesc(static_cast<uint32_t>(anchor->GetIdx()));
632+ if (GetTensorSize(desc, tensor_size) != SUCCESS) {
633+ GELOGW("HostCPU fusion internal output size is unknown: chain[%s], node[%s], output[%d].",
634+ region.chain_id.c_str(), node->GetNamePtr(), anchor->GetIdx());
635+ return UNSUPPORTED;
636+ }
637+ const size_t allocation_size = std::max<size_t>(tensor_size, 1U);
638+ const size_t remainder = internal_storage_size % kInternalBufferAlignment;
639+ const size_t padding = (remainder == 0U) ? 0U : (kInternalBufferAlignment - remainder);
640+ if ((padding > 0U) && (internal_storage_size > (std::numeric_limits<size_t>::max() - padding))) {
641+ GELOGW("HostCPU fusion internal buffer size overflow: chain[%s], node[%s].", region.chain_id.c_str(),
642+ node->GetNamePtr());
643+ return UNSUPPORTED;
644+ }
645+ internal_storage_size += padding;
646+ if (internal_storage_size > (std::numeric_limits<size_t>::max() - allocation_size)) {
647+ GELOGW("HostCPU fusion internal buffer size overflow: chain[%s], node[%s].", region.chain_id.c_str(),
648+ node->GetNamePtr());
649+ return UNSUPPORTED;
650+ }
651+ const size_t internal_index = internal_buffers.size();
652+ internal_indexes.emplace(anchor.get(), internal_index);
653+ internal_buffers.push_back({anchor, internal_storage_size});
654+ internal_storage_size += allocation_size;
672 }655 }
673 }656 }
674- code << " internal_tensors_.clear();\n"
675- << " internal_tensors_.reserve(" << internal_tensor_count << "U);\n";
676 657 
658+ // All intermediate tensors live for one Execute call. A single max-aligned
659+ // arena preserves their independent addresses while replacing hundreds of
660+ // allocator calls for wide fusion regions with one allocation. Using
661+ // max_align_t as the vector element type also makes the alignment guarantee
662+ // explicit (vector<uint8_t> only guarantees byte alignment).
663+ code << " constexpr size_t kInternalStorageAlignment = alignof(std::max_align_t);\n"
664+ << " const size_t internal_storage_words = (" << std::max<size_t>(internal_storage_size, 1U)
665+ << "U / kInternalStorageAlignment) + ((" << std::max<size_t>(internal_storage_size, 1U)
666+ << "U % kInternalStorageAlignment) == 0U ? 0U : 1U);\n"
667+ << " std::vector<std::max_align_t> internal_storage(internal_storage_words);\n"
668+ << " auto *internal_storage_data = reinterpret_cast<uint8_t *>(internal_storage.data());\n";
669+ for (size_t internal_index = 0U; internal_index < internal_buffers.size(); ++internal_index) {
670+ const auto &buffer = internal_buffers[internal_index];
671+ const auto owner = buffer.anchor->GetOwnerNode();
672+ const auto &desc = owner->GetOpDesc()->GetOutputDesc(static_cast<uint32_t>(buffer.anchor->GetIdx()));
673+ code << " gert::Tensor internal_tensor_" << internal_index << "(" << shape_expression(desc.GetShape()) << ", "
674+ << format_expression(desc) << ", gert::kOnHost, static_cast<ge::DataType>("
675+ << static_cast<int32_t>(desc.GetDataType()) << "), internal_storage_data + " << buffer.offset << "U);\n";
676+ }
677+ 
678+ std::vector<bool> kernel_type_seen(kernel_types.size(), false);
679+ gert::bg::BufferPool node_info_pool;
677 for (size_t node_index = 0U; node_index < region.nodes.size(); ++node_index) {680 for (size_t node_index = 0U; node_index < region.nodes.size(); ++node_index) {
678 const auto &node = region.nodes[node_index];681 const auto &node = region.nodes[node_index];
679 const auto op_desc = node->GetOpDesc();682 const auto op_desc = node->GetOpDesc();
680- GELOGD("Generate fused HostCPU node: chain=%s, index=%zu, node=%s, type=%s, inputs=%zu, outputs=%zu.",683+ size_t node_info_size = 0U;
681- region.chain_id.c_str(), node_index, op_desc->GetNamePtr(), op_desc->GetTypePtr(),684+ auto node_info = gert::bg::CreateComputeNodeInfo(node, node_info_pool, node_info_size);
682- op_desc->GetAllInputsSize(), op_desc->GetOutputsSize());685+ if ((node_info == nullptr) || (node_info_size == 0U)) {
683- if ((op_desc->GetName().find('\0') != std::string::npos) || (op_desc->GetType().find('\0') != std::string::npos)) {686+ GELOGW("Failed to serialize HostCPU node info: chain[%s], node[%s].", region.chain_id.c_str(),
684- GELOGE(UNSUPPORTED, "HostCPU fusion node name or type contains NUL: chain[%s], node_index[%zu], node[%s].",687+ node->GetNamePtr());
685- region.chain_id.c_str(), node_index, op_desc->GetNamePtr());
686 return UNSUPPORTED;688 return UNSUPPORTED;
687 }689 }
688- const auto in_anchors = node->GetAllInDataAnchors();
689- if (in_anchors.size() != op_desc->GetAllInputsSize()) {
690- GELOGE(PARAM_INVALID,
691- "HostCPU fusion input anchor count mismatch: chain[%s], node[%s], anchors[%zu], "
692- "op_desc_inputs[%zu].",
693- region.chain_id.c_str(), op_desc->GetNamePtr(), in_anchors.size(), op_desc->GetAllInputsSize());
694- return PARAM_INVALID;
695- }
696- std::vector<int32_t> input_binding_indices(in_anchors.size(), -1);
697- code << " std::array<const Tensor *, " << in_anchors.size() << "U> node_inputs_" << node_index << "{{";
698- for (size_t input_index = 0U; input_index < in_anchors.size(); ++input_index) {
699- const auto peer = in_anchors.at(input_index)->GetPeerOutAnchor();
700- if (peer == nullptr) {
701- GELOGE(UNSUPPORTED, "HostCPU fusion input has no peer: chain[%s], node[%s], input_index[%zu].",
702- region.chain_id.c_str(), op_desc->GetNamePtr(), input_index);
703- return UNSUPPORTED;
704- }
705- const std::string input_name = op_desc->GetInputNameByIndex(static_cast<uint32_t>(input_index));
706- if (input_name.empty() || (input_name.find('\0') != std::string::npos)) {
707- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion input name: chain[%s], node[%s], input_index[%zu].",
708- region.chain_id.c_str(), op_desc->GetNamePtr(), input_index);
709- return UNSUPPORTED;
710- }
711- if (input_index != 0U) {
712- code << ", ";
713- }
714- const auto owner = peer->GetOwnerNode();
715- const auto internal_iter = node_indexes.find(owner.get());
716- if (internal_iter != node_indexes.end()) {
717- if (internal_iter->second >= node_index) {
718- GELOGE(PARAM_INVALID,
719- "HostCPU fusion nodes are not in topological order: chain[%s], node[%s], "
720- "input_index[%zu], peer_node_index[%zu], node_index[%zu].",
721- region.chain_id.c_str(), op_desc->GetNamePtr(), input_index, internal_iter->second, node_index);
722- return PARAM_INVALID;
723- }
724- const auto source_desc = owner->GetOpDesc();
725- const std::string source_name = source_desc->GetOutputNameByIndex(static_cast<uint32_t>(peer->GetIdx()));
726- if (source_name.empty()) {
727- GELOGE(UNSUPPORTED,
728- "Invalid HostCPU fusion peer output name: chain[%s], node[%s], input_index[%zu], "
729- "peer_node[%s].",
730- region.chain_id.c_str(), op_desc->GetNamePtr(), input_index, owner->GetNamePtr());
731- return UNSUPPORTED;
732- }
733- const auto output_iter = output_indexes.find(peer.get());
734- if (output_iter != output_indexes.end()) {
735- input_binding_indices[input_index] =
736- static_cast<int32_t>(region.external_inputs.size() + output_iter->second);
737- }
738- code << "node_output_" << internal_iter->second << "_" << peer->GetIdx();
739- } else {
740- const auto external_iter = input_indexes.find(peer.get());
741- if (external_iter == input_indexes.end()) {
742- GELOGE(PARAM_INVALID,
743- "HostCPU fusion input peer is not an external input: chain[%s], node[%s], "
744- "input_index[%zu], peer_node[%s].",
745- region.chain_id.c_str(), op_desc->GetNamePtr(), input_index, owner->GetNamePtr());
746- return PARAM_INVALID;
747- }
748- input_binding_indices[input_index] = static_cast<int32_t>(external_iter->second);
749- code << "&inputs_[" << external_iter->second << "U]";
750- }
751- }
752- code << "}};\n"
753- << " std::array<int32_t, " << input_binding_indices.size() << "U> node_input_binding_indices_" << node_index
754- << "{{";
755- for (size_t input_index = 0U; input_index < input_binding_indices.size(); ++input_index) {
756- if (input_index != 0U) {
757- code << ", ";
758- }
759- code << input_binding_indices[input_index];
760- }
761- code << "}};\n";
762 690 
763- // InferShape 在融合前已经完成。这里复用已推导的 TensorDesc:区域外输出复用调用方内存,内部输出按691+ const auto kernel_type_iter = kernel_type_indexes.find(node->GetType());
764- // 静态字节数申请临时 Tensor。若大小仍未知则拒绝融合,保留原逐节点 InferShape + Kernel 执行路径。692+ if (kernel_type_iter == kernel_type_indexes.cend()) {
765- const auto out_anchors = node->GetAllOutDataAnchors();693+ GELOGE(PARAM_INVALID, "HostCPU fusion kernel type mapping is missing: chain[%s], node[%s].",
766- if (out_anchors.size() != op_desc->GetOutputsSize()) {694+ region.chain_id.c_str(), node->GetNamePtr());
767- GELOGE(PARAM_INVALID,
768- "HostCPU fusion output anchor count mismatch: chain[%s], node[%s], anchors[%zu], "
769- "op_desc_outputs[%zu].",
770- region.chain_id.c_str(), op_desc->GetNamePtr(), out_anchors.size(), op_desc->GetOutputsSize());
771 return PARAM_INVALID;695 return PARAM_INVALID;
772 }696 }
773- std::vector<int32_t> output_binding_indices(out_anchors.size(), -1);697+ code << " {\n"
774- for (size_t output_index = 0U; output_index < out_anchors.size(); ++output_index) {698+ << " static const gert::ComputeNodeInfo *const compute_node_info_" << node_index
775- const std::string output_name = op_desc->GetOutputNameByIndex(static_cast<uint32_t>(output_index));699+ << " = []() -> const gert::ComputeNodeInfo * {\n"
776- if (output_name.empty() || (output_name.find('\0') != std::string::npos)) {700+ << " alignas(gert::ComputeNodeInfo) static const std::array<uint8_t, " << node_info_size
777- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion output name: chain[%s], node[%s], output_index[%zu].",701+ << "U> node_info = []() {\n"
778- region.chain_id.c_str(), op_desc->GetNamePtr(), output_index);702+ << " alignas(gert::ComputeNodeInfo) std::array<uint8_t, " << node_info_size
779- return UNSUPPORTED;703+ << "U> info = " << emit_bytes(node_info.get(), node_info_size) << ";\n"
780- }704+ << " auto *compute_node_info = reinterpret_cast<gert::ComputeNodeInfo *>(info.data());\n"
781- const auto external_iter = output_indexes.find(out_anchors.at(output_index).get());705+ << " compute_node_info->SetNodeName(\"" << EscapeString(node->GetName()) << "\");\n"
782- if (external_iter != output_indexes.end()) {706+ << " compute_node_info->SetNodeType(\"" << EscapeString(node->GetType()) << "\");\n"
783- output_binding_indices[output_index] =707+ << " return info;\n"
784- static_cast<int32_t>(region.external_inputs.size() + external_iter->second);708+ << " }();\n"
785- GELOGD("Reuse fused external output: chain=%s, node=%s, output=%zu, fused_output=%zu.", region.chain_id.c_str(),709+ << " return reinterpret_cast<const gert::ComputeNodeInfo *>(node_info.data());\n"
786- op_desc->GetNamePtr(), output_index, external_iter->second);710+ << " }();\n"
787- code << " Tensor *node_output_" << node_index << "_" << output_index << " = &outputs_["711+ << " ";
788- << external_iter->second << "U];\n";712+ if (!kernel_type_seen[kernel_type_iter->second]) {
789- } else {713+ code << "cached_kernel_" << kernel_type_iter->second << " = GetHostKernel_" << kernel_type_iter->second
790- size_t tensor_size = 0U;714+ << "(finder);\n"
791- if (GetTensorSize(op_desc->GetOutputDesc(output_index), tensor_size) != SUCCESS) {715+ << " if (cached_kernel_" << kernel_type_iter->second << " == nullptr) { return GRAPH_FAILED; }\n"
792- GELOGD("Skip HostCPU fusion because output size is unknown after InferShape: chain=%s, node=%s, output=%zu.",716+ << " ";
793- region.chain_id.c_str(), op_desc->GetNamePtr(), output_index);717+ kernel_type_seen[kernel_type_iter->second] = true;
794- return UNSUPPORTED;
795- }
796- GELOGD("Allocate fused internal output from inferred TensorDesc: chain=%s, node=%s, output=%zu, bytes=%zu.",
797- region.chain_id.c_str(), op_desc->GetNamePtr(), output_index, tensor_size);
798- code << " internal_tensors_.emplace_back(" << TensorDescExpression(op_desc->GetOutputDesc(output_index))
799- << ", std::vector<uint8_t>(" << tensor_size << "U));\n"
800- << " Tensor *node_output_" << node_index << "_" << output_index << " = &internal_tensors_.back();\n";
801- }
802 }718 }
803- code << " std::array<Tensor *, " << out_anchors.size() << "U> node_outputs_" << node_index << "{{";719+ code << "HostKernelFunc kernel_" << node_index << " = cached_kernel_" << kernel_type_iter->second << ";\n"
804- for (size_t output_index = 0U; output_index < out_anchors.size(); ++output_index) {720+ << " const std::array<const gert::Tensor *, " << node->GetAllInDataAnchors().size() << "U> node_inputs_"
805- if (output_index != 0U) {
806- code << ", ";
807- }
808- code << "node_output_" << node_index << "_" << output_index;
809- }
810- code << "}};\n"
811- << " std::array<int32_t, " << output_binding_indices.size() << "U> node_output_binding_indices_"
812 << node_index << "{{";721 << node_index << "{{";
813- for (size_t output_index = 0U; output_index < output_binding_indices.size(); ++output_index) {722+ 
723+ const auto in_anchors = node->GetAllInDataAnchors();
724+ for (size_t input_index = 0U; input_index < in_anchors.size(); ++input_index) {
725+ const auto peer =
726+ (in_anchors.at(input_index) == nullptr) ? nullptr : in_anchors.at(input_index)->GetPeerOutAnchor();
727+ if (peer == nullptr) {
728+ GELOGW("HostCPU fusion input has no peer: chain[%s], node[%s], input[%zu].", region.chain_id.c_str(),
729+ node->GetNamePtr(), input_index);
730+ return UNSUPPORTED;
731+ }
732+ if (input_index != 0U) {
733+ code << ", ";
734+ }
735+ const auto external_iter = input_indexes.find(peer.get());
736+ if (external_iter != input_indexes.cend()) {
737+ code << "external_input_" << external_iter->second;
738+ continue;
739+ }
740+ const auto output_iter = output_indexes.find(peer.get());
741+ if (output_iter != output_indexes.cend()) {
742+ code << "external_output_" << output_iter->second;
743+ continue;
744+ }
745+ const auto internal_iter = internal_indexes.find(peer.get());
746+ if (internal_iter == internal_indexes.cend()) {
747+ GELOGE(PARAM_INVALID, "HostCPU fusion input mapping is missing: chain[%s], node[%s], input[%zu].",
748+ region.chain_id.c_str(), node->GetNamePtr(), input_index);
749+ return PARAM_INVALID;
750+ }
751+ code << "&internal_tensor_" << internal_iter->second;
752+ }
753+ code << "}};\n"
754+ << " const std::array<gert::Tensor *, " << node->GetAllOutDataAnchors().size() << "U> node_outputs_"
755+ << node_index << "{{";
756+ 
757+ const auto out_anchors = node->GetAllOutDataAnchors();
758+ for (size_t output_index = 0U; output_index < out_anchors.size(); ++output_index) {
759+ const auto &anchor = out_anchors.at(output_index);
760+ if (anchor == nullptr) {
761+ GELOGE(PARAM_INVALID, "HostCPU fusion output anchor is null: chain[%s], node[%s], output[%zu].",
762+ region.chain_id.c_str(), node->GetNamePtr(), output_index);
763+ return PARAM_INVALID;
764+ }
814 if (output_index != 0U) {765 if (output_index != 0U) {
815 code << ", ";766 code << ", ";
816 }767 }
817- code << output_binding_indices[output_index];768+ const auto external_iter = output_indexes.find(anchor.get());
769+ if (external_iter != output_indexes.cend()) {
770+ code << "external_output_" << external_iter->second;
771+ } else {
772+ const auto internal_iter = internal_indexes.find(anchor.get());
773+ if (internal_iter == internal_indexes.cend()) {
774+ GELOGE(PARAM_INVALID, "HostCPU fusion output mapping is missing: chain[%s], node[%s], output[%zu].",
775+ region.chain_id.c_str(), node->GetNamePtr(), output_index);
776+ return PARAM_INVALID;
777+ }
778+ code << "&internal_tensor_" << internal_iter->second;
779+ }
818 }780 }
819 code << "}};\n"781 code << "}};\n"
820- << " FusedHostCpuNodeOperator_" << region.chain_id << " op_" << node_index << "(\""782+ << " LocalKernelContext<" << in_anchors.size() << "U, " << out_anchors.size() << "U> kernel_context_"
821- << EscapeString(op_desc->GetName()) << "\", \"" << EscapeString(op_desc->GetType())783+ << node_index << "(compute_node_info_" << node_index << ", node_inputs_" << node_index << ", node_outputs_"
822- << "\", std::vector<std::string>{";784+ << node_index << ", kernel_" << node_index << ");\n"
823- for (size_t i = 0U; i < op_desc->GetAllInputsSize(); ++i) {785+ << " if (kernel_" << node_index << "(kernel_context_" << node_index
824- const std::string input_name = op_desc->GetInputNameByIndex(static_cast<uint32_t>(i));786+ << ".Get()) != GRAPH_SUCCESS) { return GRAPH_FAILED; }\n"
825- if (input_name.empty() || (input_name.find('\0') != std::string::npos)) {787+ << " }\n";
826- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion registered input name: chain[%s], node[%s], input_index[%zu].",
827- region.chain_id.c_str(), op_desc->GetNamePtr(), i);
828- return UNSUPPORTED;
829- }
830- if (i != 0U) {
831- code << ", ";
832- }
833- code << "std::string(\"" << EscapeString(input_name) << "\")";
834- }
835- code << "}, std::vector<std::string>{";
836- for (size_t i = 0U; i < op_desc->GetOutputsSize(); ++i) {
837- const std::string output_name = op_desc->GetOutputNameByIndex(static_cast<uint32_t>(i));
838- if (output_name.empty() || (output_name.find('\0') != std::string::npos)) {
839- GELOGE(UNSUPPORTED,
840- "Invalid HostCPU fusion registered output name: chain[%s], node[%s], "
841- "output_index[%zu].",
842- region.chain_id.c_str(), op_desc->GetNamePtr(), i);
843- return UNSUPPORTED;
844- }
845- if (i != 0U) {
846- code << ", ";
847- }
848- code << "std::string(\"" << EscapeString(output_name) << "\")";
849- }
850- code << "});\n if (op_" << node_index << ".IsEmpty()) { return GRAPH_FAILED; }\n";
851- // 仅序列化 IR 声明的计算属性,GE 调度元数据不进入融合 kernel。
852- const auto attrs = AttrUtils::GetAllAttrs(op_desc);
853- for (const auto &attr_name : op_desc->GetIrAttrNames()) {
854- if (attr_name.empty() || (attr_name.find('\0') != std::string::npos)) {
855- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion attribute name: chain[%s], node[%s].", region.chain_id.c_str(),
856- op_desc->GetNamePtr());
857- return UNSUPPORTED;
858- }
859- const auto attr_iter = attrs.find(attr_name);
860- if (attr_iter == attrs.end()) {
861- GELOGE(UNSUPPORTED, "HostCPU fusion IR attribute is missing from OpDesc: chain[%s], node[%s], attr[%s].",
862- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
863- return UNSUPPORTED;
864- }
865- const auto &attr = attr_iter->second;
866- code << " op_" << node_index << ".SetAttr(\"" << EscapeString(attr_name) << "\", ";
867- switch (attr.GetValueType()) {
868- case AnyValue::VT_INT: {
869- int64_t value = 0;
870- if (attr.GetValue<int64_t>(value) != GRAPH_SUCCESS) {
871- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion int attribute: chain[%s], node[%s], attr[%s].",
872- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
873- return UNSUPPORTED;
874- }
875- code << "static_cast<int64_t>(" << IntExpression(value) << ")";
876- break;
877- }
878- case AnyValue::VT_FLOAT: {
879- float value = 0.0F;
880- if (attr.GetValue<float>(value) != GRAPH_SUCCESS) {
881- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion float attribute: chain[%s], node[%s], attr[%s].",
882- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
883- return UNSUPPORTED;
884- }
885- if (!std::isfinite(value)) {
886- GELOGE(UNSUPPORTED, "Non-finite HostCPU fusion float attribute: chain[%s], node[%s], attr[%s].",
887- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
888- return UNSUPPORTED;
889- }
890- code << FloatExpression(value);
891- break;
892- }
893- case AnyValue::VT_BOOL: {
894- bool value = false;
895- if (attr.GetValue<bool>(value) != GRAPH_SUCCESS) {
896- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion bool attribute: chain[%s], node[%s], attr[%s].",
897- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
898- return UNSUPPORTED;
899- }
900- code << (value ? "true" : "false");
901- break;
902- }
903- case AnyValue::VT_STRING: {
904- std::string value;
905- if (attr.GetValue<std::string>(value) != GRAPH_SUCCESS) {
906- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion string attribute: chain[%s], node[%s], attr[%s].",
907- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
908- return UNSUPPORTED;
909- }
910- code << "std::string(\"" << EscapeString(value) << "\", " << value.size() << "U)";
911- break;
912- }
913- case AnyValue::VT_LIST_INT: {
914- std::vector<int64_t> value;
915- if (attr.GetValue<std::vector<int64_t>>(value) != GRAPH_SUCCESS) {
916- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion int-list attribute: chain[%s], node[%s], attr[%s].",
917- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
918- return UNSUPPORTED;
919- }
920- code << "std::vector<int64_t>" << IntVectorExpression(value);
921- break;
922- }
923- case AnyValue::VT_LIST_FLOAT: {
924- std::vector<float> value;
925- if (attr.GetValue<std::vector<float>>(value) != GRAPH_SUCCESS) {
926- GELOGE(UNSUPPORTED, "Failed to read HostCPU fusion float-list attribute: chain[%s], node[%s], attr[%s].",
927- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
928- return UNSUPPORTED;
929- }
930- if (!std::all_of(value.cbegin(), value.cend(), [](const float item) { return std::isfinite(item); })) {
931- GELOGE(UNSUPPORTED, "Non-finite HostCPU fusion float-list attribute: chain[%s], node[%s], attr[%s].",
932- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str());
933- return UNSUPPORTED;
934- }
935- code << "std::vector<float>" << FloatVectorExpression(value);
936- break;
937- }
938- default:
939- GELOGE(UNSUPPORTED, "Unsupported HostCPU fusion attribute type: chain[%s], node[%s], attr[%s], type[%d].",
940- region.chain_id.c_str(), op_desc->GetNamePtr(), attr_name.c_str(),
941- static_cast<int32_t>(attr.GetValueType()));
942- return UNSUPPORTED;
943- }
944- code << ");\n";
945- }
946 }788 }
947- code << " std::array<FusedHostCpuNodePlanDesc, " << region.nodes.size() << "U> node_descs{{\n";789+ 
948- for (size_t node_index = 0U; node_index < region.nodes.size(); ++node_index) {790+ code << " return GRAPH_SUCCESS;\n"
949- code << " {&op_" << node_index << ", node_inputs_" << node_index << ".data(), node_inputs_" << node_index
950- << ".size(), node_outputs_" << node_index << ".data(), node_outputs_" << node_index
951- << ".size(), node_input_binding_indices_" << node_index << ".data(), node_output_binding_indices_"
952- << node_index << ".data()}" << ((node_index + 1U == region.nodes.size()) ? "\n" : ",\n");
953- }
954- code << " }};\n"
955- << " void *new_plan = CreateCpuConstantFoldingFusedChainPlan(\n"
956- << " node_descs.data(), node_descs.size(), " << region.external_inputs.size() << "U, "
957- << region.external_outputs.size() << "U);\n"
958- << " if (new_plan == nullptr) { return GRAPH_FAILED; }\n"
959- << " chain_plan_.Reset(new_plan);\n"
960- << " return GRAPH_SUCCESS;\n"
961- << " }\n\n"
962- << " graphStatus Compute(const Tensor *inputs, const size_t input_num, Tensor *outputs,\n"
963- << " const size_t output_num, const bool bindings_changed) {\n"
964- << " if ((input_num != " << region.external_inputs.size()
965- << "U) || (output_num != " << region.external_outputs.size() << "U) ||\n"
966- << " ((input_num != 0U) && (inputs == nullptr)) ||\n"
967- << " ((output_num != 0U) && (outputs == nullptr))) { return GRAPH_FAILED; }\n"
968- << " const bool rebind_required = !runtime_bound_ || bindings_changed;\n"
969- << " if (rebind_required) {\n";
970- for (size_t i = 0U; i < region.external_inputs.size(); ++i) {
971- code << " inputs_[" << i << "U] = inputs[" << i << "U];\n";
972- }
973- for (size_t i = 0U; i < region.external_outputs.size(); ++i) {
974- code << " outputs_[" << i << "U] = outputs[" << i << "U];\n";
975- }
976- code << " runtime_bound_ = true;\n"
977- << " }\n"
978- << " const bool initialize_required = chain_plan_.Get() == nullptr;\n"
979- << " if (initialize_required && (Initialize() != GRAPH_SUCCESS)) { return GRAPH_FAILED; }\n"
980- << " const uint32_t binding_flags = (!initialize_required && rebind_required) ?\n"
981- << " (kFusedHostCpuShapeChanged | kFusedHostCpuDataChanged) : 0U;\n"
982- << " return Run(binding_flags);\n"
983- << " }\n\n"
984- << " graphStatus ComputeBindings(const FusedHostCpuTensorBinding *bindings,\n"
985- << " const uint32_t binding_flags) {\n"
986- << " const bool initialize_required = chain_plan_.Get() == nullptr;\n"
987- << " if (initialize_required && (InitializeBindings(bindings) != GRAPH_SUCCESS)) {\n"
988- << " return GRAPH_FAILED;\n"
989- << " }\n"
990- << " return (RunCpuConstantFoldingFusedChainPlanBindings(\n"
991- << " chain_plan_.Get(), bindings, initialize_required ? 0U : binding_flags) == 0) ?\n"
992- << " GRAPH_SUCCESS : GRAPH_FAILED;\n"
993 << " }\n"791 << " }\n"
994- << " private:\n"792+ << "};\n\n"
995- << " graphStatus InitializeBindings(const FusedHostCpuTensorBinding *bindings) {\n"793+ << "REG_OP_BACKEND(FusedHostCpuCustomOp_" << region.chain_id << ", \"" << EscapeString(register_name)
996- << " if (bindings == nullptr) { return GRAPH_FAILED; }\n";794+ << "\", ge::OpBackend::kHostCPU);\n"
997- for (size_t i = 0U; i < region.external_inputs.size(); ++i) {795+ << "} // namespace ge\n\n"
998- const auto anchor = region.external_inputs[i];796+ << "namespace {\n"
999- const auto owner = (anchor == nullptr) ? nullptr : anchor->GetOwnerNode();797+ << "ge::BaseCustomOp *CreateFusedHostCpu_" << region.chain_id
1000- const auto op_desc = (owner == nullptr) ? nullptr : owner->GetOpDesc();798+ << "() { return new (std::nothrow) ge::FusedHostCpuCustomOp_" << region.chain_id << "(); }\n"
1001- code << " if (!BuildFusedHostCpuRuntimeTensor(bindings[" << i << "U], "799+ << "struct FusedCustomOpCreatorEntry {\n"
1002- << TensorDescExpression(op_desc->GetOutputDesc(static_cast<size_t>(anchor->GetIdx()))) << ", inputs_[" << i800+ << " uint32_t struct_size;\n"
1003- << "U])) { return GRAPH_FAILED; }\n";801+ << " const char *op_type;\n"
1004- }802+ << " ge::CustomOpCreateFunc creator;\n"
1005- for (size_t i = 0U; i < region.external_outputs.size(); ++i) {803+ << " ge::OpBackend backend;\n"
1006- const auto anchor = region.external_outputs[i].source;804+ << "};\n"
1007- const auto owner = (anchor == nullptr) ? nullptr : anchor->GetOwnerNode();805+ << "} // namespace\n\n"
1008- const auto op_desc = (owner == nullptr) ? nullptr : owner->GetOpDesc();806+ << "extern \"C\" __attribute__((visibility(\"default\"))) uint32_t "
1009- code << " if (!BuildFusedHostCpuRuntimeTensor(bindings[" << (region.external_inputs.size() + i) << "U], "807+ << "GetRegisteredCustomOpCreatorAbiVersion() { return 2U; }\n"
1010- << TensorDescExpression(op_desc->GetOutputDesc(static_cast<size_t>(anchor->GetIdx()))) << ", outputs_[" << i808+ << "extern \"C\" __attribute__((visibility(\"default\"))) size_t "
1011- << "U])) { return GRAPH_FAILED; }\n";809+ << "GetRegisteredCustomOpCreatorNum() { return 1U; }\n"
1012- }810+ << "extern \"C\" __attribute__((visibility(\"default\"))) int32_t GetRegisteredCustomOpCreators(\n"
1013- code << " runtime_bound_ = true;\n"811+ << " FusedCustomOpCreatorEntry *creators, size_t creator_num, size_t creator_struct_size) {\n"
1014- << " return Initialize();\n"812+ << " if ((creators == nullptr) || (creator_num < 1U) ||\n"
1015- << " }\n"813+ << " (creator_struct_size < sizeof(FusedCustomOpCreatorEntry))) { return -1; }\n"
1016- << " graphStatus Run(const uint32_t binding_flags) {\n"814+ << " creators[0] = {sizeof(FusedCustomOpCreatorEntry), \"" << EscapeString(register_name)
1017- << " return (RunCpuConstantFoldingFusedChainPlan(chain_plan_.Get(), binding_flags) == 0) ?\n"815+ << "\", CreateFusedHostCpu_" << region.chain_id << ", ge::OpBackend::kHostCPU};\n"
1018- << " GRAPH_SUCCESS : GRAPH_FAILED;\n"816+ << " return 0;\n"
1019- << " }\n"
1020- << " FusedHostCpuChainPlanGuard chain_plan_;\n"
1021- << " std::array<Tensor, " << region.external_inputs.size() << "U> inputs_;\n"
1022- << " std::array<Tensor, " << region.external_outputs.size() << "U> outputs_;\n"
1023- << " std::vector<Tensor> internal_tensors_;\n"
1024- << " bool runtime_bound_ = false;\n"
1025- << "};\n} // namespace ge\n\n"
1026- << "namespace aicpu {\n"
1027- << "constexpr char kFusedHostCpuKernel_" << region.chain_id << "[] = \"" << EscapeString(register_name)
1028- << "\";\n"
1029- << "class FusedHostCpuKernel_" << region.chain_id << " final : public CpuKernel {\n public:\n"
1030- << " uint32_t Compute(CpuKernelContext &ctx) override {\n"
1031- << " if ((ctx.GetOpType() != kFusedHostCpuKernel_" << region.chain_id << ") ||\n"
1032- << " (ctx.GetInputsSize() != " << region.external_inputs.size() << "U) ||\n"
1033- << " (ctx.GetOutputsSize() != " << region.external_outputs.size() << "U)) { return 1U; }\n"
1034- << " static thread_local std::array<ge::Tensor, " << region.external_inputs.size() << "U> inputs;\n"
1035- << " static thread_local std::array<FusedHostCpuTensorState, " << region.external_inputs.size()
1036- << "U> input_states;\n"
1037- << " bool bindings_changed = false;\n"
1038- << " bool tensor_changed = false;\n";
1039- for (size_t i = 0U; i < region.external_inputs.size(); ++i) {
1040- code << " if (!BuildFusedHostCpuTensor(ctx.Input(" << i << "U), inputs[" << i << "U], input_states[" << i
1041- << "U], tensor_changed)) { return 1U; }\n"
1042- << " bindings_changed = bindings_changed || tensor_changed;\n";
1043- }
1044- code << " static thread_local std::array<ge::Tensor, " << region.external_outputs.size() << "U> outputs;\n"
1045- << " static thread_local std::array<FusedHostCpuTensorState, " << region.external_outputs.size()
1046- << "U> output_states;\n";
1047- for (size_t i = 0U; i < region.external_outputs.size(); ++i) {
1048- code << " if (!BuildFusedHostCpuTensor(ctx.Output(" << i << "U), outputs[" << i << "U], output_states[" << i
1049- << "U], tensor_changed)) { return 1U; }\n"
1050- << " bindings_changed = bindings_changed || tensor_changed;\n";
1051- }
1052- code << " static thread_local ge::FusedHostCpuOrchestration_" << region.chain_id << " orchestration;\n"
1053- << " const ge::graphStatus ret = orchestration.Compute(inputs.data(), inputs.size(), outputs.data(),\n"
1054- << " outputs.size(), bindings_changed);\n"
1055- << " return (ret == ge::GRAPH_SUCCESS) ? 0U : static_cast<uint32_t>(ret);\n"
1056- << " }\n};\n"
1057- << "REGISTER_CPU_KERNEL(kFusedHostCpuKernel_" << region.chain_id << ", FusedHostCpuKernel_" << region.chain_id
1058- << ");\n"
1059- << "} // namespace aicpu\n\n"
1060- << "extern \"C\" __attribute__((visibility(\"default\")))\n"
1061- << "bool ValidateFusedHostCpuKernelRegistration(const char *register_name) {\n"
1062- << " if ((register_name == nullptr) ||\n"
1063- << " (std::strcmp(register_name, aicpu::kFusedHostCpuKernel_" << region.chain_id
1064- << ") != 0)) { return false; }\n"
1065- << " const auto kernel = aicpu::CpuKernelRegister::Instance().GetCpuKernel(register_name);\n"
1066- << " return std::dynamic_pointer_cast<aicpu::FusedHostCpuKernel_" << region.chain_id
1067- << ">(kernel) != nullptr;\n"
1068- << "}\n\n"
1069- << "extern \"C\" __attribute__((visibility(\"default\")))\n"
1070- << "void *CreateFusedHostCpuKernelState() {\n"
1071- << " std::unique_ptr<ge::FusedHostCpuOrchestration_" << region.chain_id
1072- << "> state(new (std::nothrow) ge::FusedHostCpuOrchestration_" << region.chain_id << "());\n"
1073- << " if (state == nullptr) { return nullptr; }\n"
1074- << " return state.release();\n"
1075- << "}\n\n"
1076- << "extern \"C\" __attribute__((visibility(\"default\")))\n"
1077- << "void DestroyFusedHostCpuKernelState(void *kernel_state) {\n"
1078- << " delete static_cast<ge::FusedHostCpuOrchestration_" << region.chain_id << " *>(kernel_state);\n"
1079- << "}\n\n"
1080- << "extern \"C\" __attribute__((visibility(\"default\")))\n"
1081- << "uint32_t RunFusedHostCpuKernel(void *kernel_state, const void *binding_data,\n"
1082- << " const uint32_t binding_flags) {\n"
1083- << " if (kernel_state == nullptr) { return 1U; }\n"
1084- << " const auto *bindings = static_cast<const FusedHostCpuTensorBinding *>(binding_data);\n"
1085- << " auto *state = static_cast<ge::FusedHostCpuOrchestration_" << region.chain_id << " *>(kernel_state);\n"
1086- << " const ge::graphStatus ret = state->ComputeBindings(bindings, binding_flags);\n"
1087- << " return (ret == ge::GRAPH_SUCCESS) ? 0U : static_cast<uint32_t>(ret);\n"
1088 << "}\n";817 << "}\n";
1089- const std::string source = code.str();818+ 
1090- if (source.size() > kMaxGeneratedSourceSize) {819+ result.register_name = register_name;
1091- GELOGE(UNSUPPORTED, "HostCPU fusion generated source is too large: chain[%s], source_size[%zu], limit[%zu].",820+ result.source = code.str();
1092- region.chain_id.c_str(), source.size(), kMaxGeneratedSourceSize);821+ if (result.source.size() > kMaxGeneratedSourceSize) {
822+ GELOGW("HostCPU fusion generated source is too large: chain[%s], source_size[%zu], limit[%zu].",
823+ region.chain_id.c_str(), result.source.size(), kMaxGeneratedSourceSize);
824+ result = {};
1093 return UNSUPPORTED;825 return UNSUPPORTED;
1094 }826 }
1095- result.register_name = register_name;827+ GELOGD("Generated HostCPU custom-op source: chain=%s, op_type=%s, source_size=%zu.", region.chain_id.c_str(),
1096- result.source = source;828+ register_name.c_str(), result.source.size());
1097- GELOGD("Generated HostCPU fusion source: chain=%s, register_name=%s, source_size=%zu.", region.chain_id.c_str(),
1098- register_name.c_str(), source.size());
1099- GELOGD("Generated HostCPU fusion source:\n%s", source.c_str());
1100 return SUCCESS;829 return SUCCESS;
1101}830}
1102 831 
1103-// NOLINTNEXTLINE(huge_method, huge_cyclomatic_complexity): compiler process setup must remain one failure-atomic path.
1104Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uint8_t> &so_data) const {832Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uint8_t> &so_data) const {
1105 so_data.clear();833 so_data.clear();
1106#if !defined(__linux__)834#if !defined(__linux__)
@@ -1116,12 +844,11 @@ Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uin
1116 844 
1117 // 校验源码845 // 校验源码
1118 if (source.empty() || (source.size() > kMaxGeneratedSourceSize)) {846 if (source.empty() || (source.size() > kMaxGeneratedSourceSize)) {
1119- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion JIT source: source_size[%zu], limit[%zu].", source.size(),847+ GELOGW("Invalid HostCPU fusion JIT source: source_size[%zu], limit[%zu].", source.size(), kMaxGeneratedSourceSize);
1120- kMaxGeneratedSourceSize);
1121 return UNSUPPORTED;848 return UNSUPPORTED;
1122 }849 }
1123 if (include_paths.empty()) {850 if (include_paths.empty()) {
1124- GELOGE(UNSUPPORTED, "HostCPU fusion JIT include path is empty, check ASCEND_OPP_PATH or ASCEND_HOME_PATH.");851+ GELOGW("HostCPU fusion JIT include path is empty, check ASCEND_OPP_PATH or ASCEND_HOME_PATH.");
1125 return UNSUPPORTED;852 return UNSUPPORTED;
1126 }853 }
1127 GELOGD("Compile HostCPU fusion source: compiler=%s, target_cpu=%s, source_size=%zu, include_paths=%s.",854 GELOGD("Compile HostCPU fusion source: compiler=%s, target_cpu=%s, source_size=%zu, include_paths=%s.",
@@ -1187,7 +914,8 @@ Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uin
1187 compiler_args.emplace_back("-I");914 compiler_args.emplace_back("-I");
1188 compiler_args.emplace_back(include_path);915 compiler_args.emplace_back(include_path);
1189 }916 }
1190- compiler_args.insert(compiler_args.end(), {"-x", "c++", source_path, "-o", so_path});917+ // Keep libdl after the generated object input so linkers using --as-needed retain it.
918+ compiler_args.insert(compiler_args.end(), {"-x", "c++", source_path, "-ldl", "-o", so_path});
1191 // 构造 execvp()参数919 // 构造 execvp()参数
1192 std::vector<const char *> exec_argv;920 std::vector<const char *> exec_argv;
1193 exec_argv.reserve(compiler_args.size() + 1U);921 exec_argv.reserve(compiler_args.size() + 1U);
@@ -1220,8 +948,8 @@ Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uin
1220 if (!wait_success || !WIFEXITED(child_status) || (WEXITSTATUS(child_status) != 0)) {948 if (!wait_success || !WIFEXITED(child_status) || (WEXITSTATUS(child_status) != 0)) {
1221 const int exit_code = (wait_success && WIFEXITED(child_status)) ? WEXITSTATUS(child_status) : -1;949 const int exit_code = (wait_success && WIFEXITED(child_status)) ? WEXITSTATUS(child_status) : -1;
1222 const std::string diagnostics = ReadCompilerDiagnostics(diagnostics_fd);950 const std::string diagnostics = ReadCompilerDiagnostics(diagnostics_fd);
1223- GELOGE(UNSUPPORTED, "HostCPU fusion compiler %s failed, exit_code=%d, diagnostics=%s.", compiler_name.c_str(),951+ GELOGW("HostCPU fusion compiler %s failed, exit_code=%d, diagnostics=%s.", compiler_name.c_str(), exit_code,
1224- exit_code, diagnostics.c_str());952+ diagnostics.c_str());
1225 status = UNSUPPORTED;953 status = UNSUPPORTED;
1226 break;954 break;
1227 }955 }
@@ -1229,7 +957,7 @@ Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uin
1229 // 检查.so大小 0 < so_size <= 10 MB 空文件、超过 10 MB 或 lseek失败957 // 检查.so大小 0 < so_size <= 10 MB 空文件、超过 10 MB 或 lseek失败
1230 const off_t so_size = lseek(so_fd, 0, SEEK_END);958 const off_t so_size = lseek(so_fd, 0, SEEK_END);
1231 if ((so_size <= 0) || (static_cast<uint64_t>(so_size) > kMaxGeneratedSoSize) || (lseek(so_fd, 0, SEEK_SET) < 0)) {959 if ((so_size <= 0) || (static_cast<uint64_t>(so_size) > kMaxGeneratedSoSize) || (lseek(so_fd, 0, SEEK_SET) < 0)) {
1232- GELOGE(UNSUPPORTED, "Invalid HostCPU fusion compiler output: so_size[%lld], limit[%zu], errno[%d].",960+ GELOGW("Invalid HostCPU fusion compiler output: so_size[%lld], limit[%zu], errno[%d].",
1233 static_cast<long long>(so_size), kMaxGeneratedSoSize, errno);961 static_cast<long long>(so_size), kMaxGeneratedSoSize, errno);
1234 break;962 break;
1235 }963 }
@@ -1251,8 +979,8 @@ Status HostCpuFusionCompiler::Compile(const std::string &source, std::vector<uin
1251 offset += static_cast<size_t>(read_size);979 offset += static_cast<size_t>(read_size);
1252 }980 }
1253 if (!IsExpectedElf(so_data, target_cpu)) {981 if (!IsExpectedElf(so_data, target_cpu)) {
1254- GELOGE(UNSUPPORTED, "HostCPU fusion compiler output is not an expected ELF: target_cpu[%s], so_size[%zu].",982+ GELOGW("HostCPU fusion compiler output is not an expected ELF: target_cpu[%s], so_size[%zu].", target_cpu.c_str(),
1255- target_cpu.c_str(), so_data.size());983+ so_data.size());
1256 so_data.clear();984 so_data.clear();
1257 break;985 break;
1258 }986 }
@@ -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 写入图属性并在运行时加载37+// source 用于维测和测试,so_data 作为标准 custom-op SO 写入模型
38struct HostCpuFusionCodegenResult {38struct 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-// 生成注册到 aicpu::CpuKernelRegister融合 CpuKernel;内部编排为每个原始算子缓存 CpuKernel 执行计划,53+// 生成注册到 CustomOpRegistry(kHostCPU)普通 HostCpuExecuteOp。执行时按 op_type 从
54-// 稳态仅更新 Tensor 数据和变化的描述信息并按拓扑序执行。54+// libconstant_folding_ops.so 查询 Gert HostKernel,使用临时 KernelContext 按拓扑序执行。
55class HostCpuFusionCodegen {55class HostCpuFusionCodegen {
56 public:56 public:
57 Status Generate(const HostCpuFusionRegion &region, HostCpuFusionCodegenResult &result) const;57 Status Generate(const HostCpuFusionRegion &region, HostCpuFusionCodegenResult &result) const;
@@ -14,14 +14,23 @@
14#include <cstdint>14#include <cstdint>
15#include <deque>15#include <deque>
16#include <iomanip>16#include <iomanip>
17+#include <limits>
18+#include <map>
19+#include <memory>
17#include <sstream>20#include <sstream>
18#include <unordered_map>21#include <unordered_map>
19#include <unordered_set>22#include <unordered_set>
20 23 
21#include "framework/common/debug/ge_log.h"24#include "framework/common/debug/ge_log.h"
22#include "framework/common/host_cpu_fusion_attr.h"25#include "framework/common/host_cpu_fusion_attr.h"
26+#include "common/ge_common/ge_types.h"
27+#include "common/helper/custom_op_registry_builder.h"
28+#include "common/helper/custom_op_so_loader.h"
29+#include "common/util/mem_utils.h"
23#include "host_cpu_engine/host_cpu_engine.h"30#include "host_cpu_engine/host_cpu_engine.h"
31+#include "graph/custom_op_factory.h"
24#include "graph/debug/ge_attr_define.h"32#include "graph/debug/ge_attr_define.h"
33+#include "graph/op_so_bin.h"
25#include "graph/utils/attr_utils.h"34#include "graph/utils/attr_utils.h"
26#include "graph/utils/graph_utils.h"35#include "graph/utils/graph_utils.h"
27#include "graph/utils/node_utils.h"36#include "graph/utils/node_utils.h"
@@ -31,10 +40,9 @@ namespace {
31constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U;40constexpr size_t kMaxGeneratedSoSize = 10U * 1024U * 1024U;
32constexpr char kHostCpuEngineName[] = "DNN_VM_HOST_CPU";41constexpr char kHostCpuEngineName[] = "DNN_VM_HOST_CPU";
33constexpr char kHostCpuKernelLibName[] = "DNN_VM_HOST_CPU_OP_STORE";42constexpr char kHostCpuKernelLibName[] = "DNN_VM_HOST_CPU_OP_STORE";
34-constexpr char kHostCpuTaskKernelLibName[] = "HOSTCPUKernel";
35-constexpr char kOpKernelLibAttr[] = "opKernelLib";
36constexpr char kSmallShapeHostCpu[] = "SmallShapeHostcpu";43constexpr char kSmallShapeHostCpu[] = "SmallShapeHostcpu";
37constexpr char kResourceListAttr[] = "_resource_list";44constexpr char kResourceListAttr[] = "_resource_list";
45+constexpr char kSoBufferAttr[] = "bin_file_buffer";
38 46 
39bool IsValidFusedHostCpuSoElf(const std::vector<uint8_t> &data) {47bool IsValidFusedHostCpuSoElf(const std::vector<uint8_t> &data) {
40 return (data.size() >= 20U) && (data.size() <= kMaxGeneratedSoSize) && (data[0] == 0x7FU) && (data[1] == 'E') &&48 return (data.size() >= 20U) && (data.size() <= kMaxGeneratedSoSize) && (data[0] == 0x7FU) && (data[1] == 'E') &&
@@ -132,7 +140,8 @@ bool IsCandidate(const NodePtr &node, const HostCpuFusionOpSupportChecker &op_su
132 GELOGD("Skip HostCPU fusion node[%s]: OpDesc is null.", node->GetNamePtr());140 GELOGD("Skip HostCPU fusion node[%s]: OpDesc is null.", node->GetNamePtr());
133 return false;141 return false;
134 }142 }
135- if (node->GetType() == kFusedHostCpuOpType) {143+ bool generated = false;
144+ if (AttrUtils::GetBool(node->GetOpDesc(), kFusedHostCpuGenerated, generated) && generated) {
136 GELOGD("Skip HostCPU fusion node[%s]: node is already fused.", node->GetNamePtr());145 GELOGD("Skip HostCPU fusion node[%s]: node is already fused.", node->GetNamePtr());
137 return false;146 return false;
138 }147 }
@@ -318,10 +327,15 @@ std::vector<NodePtr> GetComponentSinks(const std::vector<NodePtr> &component,
318 return sinks;327 return sinks;
319}328}
320 329 
321-HostCpuFusionRegion BuildRegionForSink(const std::vector<NodePtr> &topological_nodes,330+std::unordered_set<const Node *> CollectComponentAncestors(const std::unordered_set<const Node *> &component_set,
322- const std::unordered_set<const Node *> &component_set, const NodePtr &sink) {331+ const NodePtr &sink) {
323 std::unordered_set<const Node *> ancestors;332 std::unordered_set<const Node *> ancestors;
324- std::deque<NodePtr> pending{sink};333+ std::deque<NodePtr> pending;
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+ }
325 while (!pending.empty()) {339 while (!pending.empty()) {
326 const auto current = pending.front();340 const auto current = pending.front();
327 pending.pop_front();341 pending.pop_front();
@@ -334,10 +348,46 @@ HostCpuFusionRegion BuildRegionForSink(const std::vector<NodePtr> &topological_n
334 }348 }
335 }349 }
336 }350 }
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+ }
337 387 
338 HostCpuFusionRegion region;388 HostCpuFusionRegion region;
339 for (const auto &node : topological_nodes) {389 for (const auto &node : topological_nodes) {
340- if (ancestors.count(node.get()) > 0U) {390+ if (region_nodes.count(node.get()) > 0U) {
341 region.nodes.emplace_back(node);391 region.nodes.emplace_back(node);
342 }392 }
343 }393 }
@@ -419,14 +469,17 @@ Status BuildComponentRegions(const ComputeGraphPtr &graph, const std::vector<Nod
419 sinks.size());469 sinks.size());
420 return FAILED;470 return FAILED;
421 }471 }
422- GELOGD("HostCPU fusion component[%zu] contains %zu nodes and %zu sinks, clone_and_split=%d, nodes=[%s].",472+ GELOGD("HostCPU fusion component[%zu] contains %zu nodes and %zu sinks, ancestor_grouping=%d, nodes=[%s].",
423 component_index, component.size(), sinks.size(), static_cast<int32_t>(requires_split),473 component_index, component.size(), sinks.size(), static_cast<int32_t>(requires_split),
424 GetNodeNames(component).c_str());474 GetNodeNames(component).c_str());
425- for (const auto &sink : sinks) {475+ const auto sink_groups = GroupSinksByAncestors(component_set, sinks);
426- auto region = BuildRegionForSink(topological_nodes, component_set, sink);476+ GELOGD("HostCPU fusion component[%zu] groups %zu sinks into %zu ancestor group(s).", component_index, sinks.size(),
477+ sink_groups.size());
478+ for (const auto &group : sink_groups) {
479+ auto region = BuildRegionForSinkGroup(topological_nodes, group);
427 if (region.nodes.size() < 2U) {480 if (region.nodes.size() < 2U) {
428- GELOGD("Skip HostCPU fusion component[%zu] sink[%s]: ancestor region has only %zu node(s).", component_index,481+ GELOGD("Skip HostCPU fusion component[%zu] sink group[%s]: ancestor region has only %zu node(s).",
429- sink->GetNamePtr(), region.nodes.size());482+ component_index, GetNodeNames(group.sinks).c_str(), region.nodes.size());
430 continue;483 continue;
431 }484 }
432 regions.emplace_back(std::move(region));485 regions.emplace_back(std::move(region));
@@ -480,16 +533,15 @@ bool AddFusedOutputDescs(const HostCpuFusionRegion &region, const OpDescPtr &op_
480}533}
481 534 
482bool SetFusedOpAttributes(const PreparedFusionRegion &prepared, const OpDescPtr &op_desc) {535bool SetFusedOpAttributes(const PreparedFusionRegion &prepared, const OpDescPtr &op_desc) {
483- const auto &region = prepared.region;536+ op_desc->SetOpEngineName(kEngineNameCustom);
484- op_desc->SetOpEngineName(kHostCpuEngineName);537+ op_desc->SetOpKernelLibName(kCustomOpKernelLibName);
485- op_desc->SetOpKernelLibName(kHostCpuKernelLibName);538+ return AttrUtils::SetStr(op_desc, ATTR_NAME_ENGINE_NAME_FOR_LX, kEngineNameCustom) &&
486- return AttrUtils::SetStr(op_desc, ATTR_NAME_ENGINE_NAME_FOR_LX, kHostCpuEngineName) &&539+ AttrUtils::SetStr(op_desc, ATTR_NAME_KKERNEL_LIB_NAME_FOR_LX, kCustomOpKernelLibName) &&
487- AttrUtils::SetStr(op_desc, ATTR_NAME_KKERNEL_LIB_NAME_FOR_LX, kHostCpuKernelLibName) &&540+ AttrUtils::SetStr(op_desc, kAttrLowingFunc, kHostCpuCustomOpLowerFunc) &&
488- AttrUtils::SetStr(op_desc, kOpKernelLibAttr, kHostCpuTaskKernelLibName) &&
489 AttrUtils::SetInt(op_desc, ATTR_NAME_UNKNOWN_SHAPE_TYPE, DEPEND_IN_SHAPE) &&541 AttrUtils::SetInt(op_desc, ATTR_NAME_UNKNOWN_SHAPE_TYPE, DEPEND_IN_SHAPE) &&
490 AttrUtils::SetBool(op_desc, kSmallShapeHostCpu, true) &&542 AttrUtils::SetBool(op_desc, kSmallShapeHostCpu, true) &&
491- AttrUtils::SetStr(op_desc, kFusedHostCpuRegisterName, prepared.codegen.register_name) &&543+ AttrUtils::SetBool(op_desc, kFusedHostCpuGenerated, true) &&
492- AttrUtils::SetStr(op_desc, kFusedHostCpuSoKey, std::string(kFusedHostCpuSoDataPrefix) + region.chain_id);544+ AttrUtils::SetStr(op_desc, kFusedHostCpuRegisterName, prepared.codegen.register_name);
493}545}
494 546 
495bool SetFusedOpMetadata(const HostCpuFusionRegion &region, const OpDescPtr &op_desc) {547bool SetFusedOpMetadata(const HostCpuFusionRegion &region, const OpDescPtr &op_desc) {
@@ -512,8 +564,7 @@ bool SetFusedOpMetadata(const HostCpuFusionRegion &region, const OpDescPtr &op_d
512 564 
513OpDescPtr CreateFusedOpDesc(const PreparedFusionRegion &prepared) {565OpDescPtr CreateFusedOpDesc(const PreparedFusionRegion &prepared) {
514 const auto &region = prepared.region;566 const auto &region = prepared.region;
515- auto op_desc =567+ auto op_desc = std::make_shared<OpDesc>(prepared.codegen.register_name, prepared.codegen.register_name);
516- std::make_shared<OpDesc>(std::string(kFusedHostCpuOpType) + "_" + region.chain_id, kFusedHostCpuOpType);
517 if (!AddFusedInputDescs(region, op_desc) || !AddFusedOutputDescs(region, op_desc)) {568 if (!AddFusedInputDescs(region, op_desc) || !AddFusedOutputDescs(region, op_desc)) {
518 return nullptr;569 return nullptr;
519 }570 }
@@ -548,10 +599,8 @@ struct ReplacedFusionOutput {
548 OutDataAnchorPtr new_source;599 OutDataAnchorPtr new_source;
549};600};
550 601 
551-Status RollbackFusionCommit(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph,602+Status RollbackFusionCommit(const ComputeGraphPtr &graph, const std::vector<NodePtr> &fused_nodes,
552- const std::vector<NodePtr> &fused_nodes,603+ const std::vector<ReplacedFusionOutput> &replaced_outputs) {
553- const std::vector<ReplacedFusionOutput> &replaced_outputs,
554- const std::vector<std::string> &root_graph_so_keys) {
555 GELOGW("Rollback HostCPU fusion graph commit: graph[%s], new_nodes=%zu, replaced_edges=%zu.",604 GELOGW("Rollback HostCPU fusion graph commit: graph[%s], new_nodes=%zu, replaced_edges=%zu.",
556 graph->GetName().c_str(), fused_nodes.size(), replaced_outputs.size());605 graph->GetName().c_str(), fused_nodes.size(), replaced_outputs.size());
557 for (auto iter = replaced_outputs.rbegin(); iter != replaced_outputs.rend(); ++iter) {606 for (auto iter = replaced_outputs.rbegin(); iter != replaced_outputs.rend(); ++iter) {
@@ -560,28 +609,10 @@ Status RollbackFusionCommit(const ComputeGraphPtr &graph, const ComputeGraphPtr
560 graph->GetName().c_str(), static_cast<int32_t>(iter->consumer == nullptr));609 graph->GetName().c_str(), static_cast<int32_t>(iter->consumer == nullptr));
561 }610 }
562 }611 }
563- const Status rollback_status = RollbackNewNodes(graph, fused_nodes);612+ return 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;
571}613}
572 614 
573-NodePtr CreateAndRegisterFusedNode(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph,615+NodePtr CreateFusedNode(const ComputeGraphPtr &graph, const PreparedFusionRegion &prepared) {
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);
585 const auto op_desc = CreateFusedOpDesc(prepared);616 const auto op_desc = CreateFusedOpDesc(prepared);
586 if (op_desc == nullptr) {617 if (op_desc == nullptr) {
587 GELOGE(FAILED, "Failed to create fused HostCPU OpDesc: graph[%s], chain[%s].", graph->GetName().c_str(),618 GELOGE(FAILED, "Failed to create fused HostCPU OpDesc: graph[%s], chain[%s].", graph->GetName().c_str(),
@@ -599,10 +630,9 @@ NodePtr CreateAndRegisterFusedNode(const ComputeGraphPtr &graph, const ComputeGr
599 op_desc->GetName().c_str());630 op_desc->GetName().c_str());
600 return nullptr;631 return nullptr;
601 }632 }
602- GELOGD("HostCPU fusion adds node[%s]: chain[%s], so_key[%s], so_graph[%s], so_size=%zu, inputs=%zu, outputs=%zu.",633+ GELOGD("HostCPU fusion adds custom-op node[%s]: chain[%s], so_size=%zu, inputs=%zu, outputs=%zu.",
603- fused_node->GetNamePtr(), prepared.region.chain_id.c_str(), so_key.c_str(), root_graph->GetName().c_str(),634+ fused_node->GetNamePtr(), prepared.region.chain_id.c_str(), prepared.codegen.so_data.size(),
604- prepared.codegen.so_data.size(), prepared.region.external_inputs.size(),635+ prepared.region.external_inputs.size(), prepared.region.external_outputs.size());
605- prepared.region.external_outputs.size());
606 return fused_node;636 return fused_node;
607}637}
608 638 
@@ -641,12 +671,9 @@ bool ReplaceFusedNodeOutputs(const ComputeGraphPtr &graph, const PreparedFusionR
641 return true;671 return true;
642}672}
643 673 
644-bool AddPreparedFusionNode(const ComputeGraphPtr &graph, const ComputeGraphPtr &root_graph,674+bool AddPreparedFusionNode(const ComputeGraphPtr &graph, const PreparedFusionRegion &prepared,
645- const PreparedFusionRegion &prepared, std::vector<NodePtr> &fused_nodes,675+ std::vector<NodePtr> &fused_nodes, std::vector<ReplacedFusionOutput> &replaced_outputs) {
646- std::vector<std::string> &root_graph_so_keys,676+ const auto fused_node = CreateFusedNode(graph, prepared);
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);
650 if (fused_node == nullptr) {677 if (fused_node == nullptr) {
651 return false;678 return false;
652 }679 }
@@ -685,6 +712,107 @@ bool RemoveOriginalFusionNodes(const ComputeGraphPtr &graph, const std::vector<P
685 return true;712 return true;
686}713}
687 714 
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+ 
688Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<PreparedFusionRegion> &prepared_regions,816Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<PreparedFusionRegion> &prepared_regions,
689 NodeEngineMap &node_atomic_engine_map, NodeEngineMap &node_composite_engine_map) {817 NodeEngineMap &node_atomic_engine_map, NodeEngineMap &node_composite_engine_map) {
690 const auto root_graph = GraphUtils::FindRootGraph(graph);818 const auto root_graph = GraphUtils::FindRootGraph(graph);
@@ -692,19 +820,23 @@ Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<Prepa
692 GELOGE(FAILED, "Failed to find root graph when committing HostCPU fusion for graph %s.", graph->GetName().c_str());820 GELOGE(FAILED, "Failed to find root graph when committing HostCPU fusion for graph %s.", graph->GetName().c_str());
693 return FAILED;821 return FAILED;
694 }822 }
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());
695 std::vector<NodePtr> fused_nodes;826 std::vector<NodePtr> fused_nodes;
696- std::vector<std::string> root_graph_so_keys;
697 std::vector<ReplacedFusionOutput> replaced_outputs;827 std::vector<ReplacedFusionOutput> replaced_outputs;
698 GELOGD("HostCPU fusion starts graph commit: graph[%s], regions=%zu.", graph->GetName().c_str(),828 GELOGD("HostCPU fusion starts graph commit: graph[%s], regions=%zu.", graph->GetName().c_str(),
699 prepared_regions.size());829 prepared_regions.size());
700 for (const auto &prepared : prepared_regions) {830 for (const auto &prepared : prepared_regions) {
701- if (!AddPreparedFusionNode(graph, root_graph, prepared, fused_nodes, root_graph_so_keys, replaced_outputs)) {831+ if (!AddPreparedFusionNode(graph, prepared, fused_nodes, replaced_outputs)) {
702- (void)RollbackFusionCommit(graph, root_graph, fused_nodes, replaced_outputs, root_graph_so_keys);832+ (void)RollbackFusionCommit(graph, fused_nodes, replaced_outputs);
833+ RollbackFusionCustomOpArtifacts(root_graph, artifacts);
703 return FAILED;834 return FAILED;
704 }835 }
705 }836 }
706 if (!ValidateFusionGraph(graph, "transition")) {837 if (!ValidateFusionGraph(graph, "transition")) {
707- (void)RollbackFusionCommit(graph, root_graph, fused_nodes, replaced_outputs, root_graph_so_keys);838+ (void)RollbackFusionCommit(graph, fused_nodes, replaced_outputs);
839+ RollbackFusionCustomOpArtifacts(root_graph, artifacts);
708 return FAILED;840 return FAILED;
709 }841 }
710 GELOGD("HostCPU fusion transition graph validation passed: graph[%s], fused_nodes=%zu.", graph->GetName().c_str(),842 GELOGD("HostCPU fusion transition graph validation passed: graph[%s], fused_nodes=%zu.", graph->GetName().c_str(),
@@ -714,8 +846,8 @@ Status CommitFusionRegions(const ComputeGraphPtr &graph, const std::vector<Prepa
714 return FAILED;846 return FAILED;
715 }847 }
716 for (const auto &node : fused_nodes) {848 for (const auto &node : fused_nodes) {
717- node_atomic_engine_map[node] = kHostCpuEngineName;849+ node_atomic_engine_map[node] = kEngineNameCustom;
718- node_composite_engine_map[node] = kHostCpuEngineName;850+ node_composite_engine_map[node] = kEngineNameCustom;
719 }851 }
720 if (!ValidateFusionGraph(graph, "final")) {852 if (!ValidateFusionGraph(graph, "final")) {
721 return FAILED;853 return FAILED;
@@ -734,7 +866,7 @@ HostCpuFusionPass::HostCpuFusionPass(std::shared_ptr<HostCpuFusionCompiler> comp
734 }866 }
735 if (op_support_checker_ == nullptr) {867 if (op_support_checker_ == nullptr) {
736 op_support_checker_ = [](const std::string &op_type) {868 op_support_checker_ = [](const std::string &op_type) {
737- return HostCpuEngine::GetInstance().IsFusedCpuKernelSupported(op_type);869+ return HostCpuEngine::GetInstance().IsHostKernelSupported(op_type);
738 };870 };
739 }871 }
740}872}
@@ -35,7 +35,7 @@ ge::OpDescPtr GetOpDescPtr(const HostCpuOpExecutionContext &ctx) {
35 const auto node_type = ctx.GetNodeType();35 const auto node_type = ctx.GetNodeType();
36 auto const node_op = ge::OperatorFactory::CreateOperator("_", node_type);36 auto const node_op = ge::OperatorFactory::CreateOperator("_", node_type);
37 if (node_op.IsEmpty()) {37 if (node_op.IsEmpty()) {
38- GELOGE(ge::FAILED, "get op from OperatorFactory fail. opType: %s", node_type);38+ GELOGW("get op from OperatorFactory fail. opType: %s", node_type);
39 return nullptr;39 return nullptr;
40 }40 }
41 GELOGD("get op from OperatorFactory success. opType is %s", node_type);41 GELOGD("get op from OperatorFactory success. opType is %s", node_type);
@@ -12,11 +12,11 @@
12#define INC_FRAMEWORK_COMMON_HOST_CPU_FUSION_ATTR_H_12#define INC_FRAMEWORK_COMMON_HOST_CPU_FUSION_ATTR_H_
13 13 
14namespace ge {14namespace ge {
15-// Compiler、HostCPU Builder 和 RT2 通过这些属性传递 FusedHostCpu 内部序列化信息15+// Compiler 和 RT2 通过这些属性识别由 HostCPU 融合生成的普通 HostCPU 自定义算子
16constexpr char kFusedHostCpuOpType[] = "FusedHostCpu";16constexpr char kFusedHostCpuOpType[] = "FusedHostCpu";
17constexpr char kFusedHostCpuRegisterName[] = "_host_cpu_fusion_register_name";17constexpr char kFusedHostCpuRegisterName[] = "_host_cpu_fusion_register_name";
18-constexpr char kFusedHostCpuSoKey[] = "_host_cpu_fusion_so_key";18+constexpr char kFusedHostCpuGenerated[] = "_host_cpu_fusion_generated";
19-constexpr char kFusedHostCpuSoDataPrefix[] = "_hostcpu_codegen_so_data_";19+constexpr char kFusedHostCpuSoVendor[] = "host_cpu_fusion";
20constexpr char kFusedHostCpuOriginalNodes[] = "_host_cpu_fusion_original_nodes";20constexpr char kFusedHostCpuOriginalNodes[] = "_host_cpu_fusion_original_nodes";
21constexpr char kFusedHostCpuOriginalTypes[] = "_host_cpu_fusion_original_types";21constexpr char kFusedHostCpuOriginalTypes[] = "_host_cpu_fusion_original_types";
22constexpr char kFusedHostCpuOutputRefs[] = "_host_cpu_fusion_output_refs";22constexpr char kFusedHostCpuOutputRefs[] = "_host_cpu_fusion_output_refs";
@@ -97,6 +97,12 @@ ge::Status CreateSoPathHolder(const ge::NodePtr &node, bg::ValueHolderPtr &so_pa
97 }97 }
98 auto buffer = bin_file_buffer->find(so_path);98 auto buffer = bin_file_buffer->find(so_path);
99 if (buffer == bin_file_buffer->end()) {99 if (buffer == bin_file_buffer->end()) {
100+ // bin_file_buffer 可能还包含 HostCPU fusion 的 kCustomOp SO
101+ if (mmAccess(so_path.c_str()) == EN_OK) {
102+ GELOGD("Autofuse SO is not embedded, use file path: %s.", so_path.c_str());
103+ return ge::SUCCESS;
104+ }
105+ 
100 GELOGE(ge::FAILED, "Not exist autofuse so in bin_file_buffer, key:%s.", so_path.c_str());106 GELOGE(ge::FAILED, "Not exist autofuse so in bin_file_buffer, key:%s.", so_path.c_str());
101 return ge::FAILED;107 return ge::FAILED;
102 }108 }
@@ -29,11 +29,7 @@
29#include "register/kernel_registry.h"29#include "register/kernel_registry.h"
30#include "graph_builder/bg_rt_session.h"30#include "graph_builder/bg_rt_session.h"
31#include "engine/aicpu/kernel/aicpu_resource_manager.h"31#include "engine/aicpu/kernel/aicpu_resource_manager.h"
32-#include "engine/aicpu/kernel/fused_host_cpu_compute.h"
33#include "graph/utils/graph_utils.h"32#include "graph/utils/graph_utils.h"
34-#include "rt_external_mem.h"
35-#include "exe_graph/lowering/frame_selector.h"
36-#include "framework/common/host_cpu_fusion_attr.h"
37 33 
38namespace gert {34namespace gert {
39namespace {35namespace {
@@ -246,133 +242,11 @@ LowerResult LoweringAiCpuCCNode(const ge::NodePtr &node, const LowerInput &lower
246 return {HyperStatus::Success(), {cc_launch_holder, launch_holder}, node_output.shapes, out_addrs};242 return {HyperStatus::Success(), {cc_launch_holder, launch_holder}, node_output.shapes, out_addrs};
247}243}
248 244 
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- 
368struct HostAiCpuLoweringData {245struct HostAiCpuLoweringData {
369 const domi::KernelDef *kernel_def = nullptr;246 const domi::KernelDef *kernel_def = nullptr;
370 bg::ValueHolderPtr session_id;247 bg::ValueHolderPtr session_id;
371 bg::AicpuArgs aicpu_args;248 bg::AicpuArgs aicpu_args;
372 size_t in_num = 0U;249 size_t in_num = 0U;
373- bool is_fused_host_cpu = false;
374- std::string fused_register_name;
375- void *fused_compute_state = nullptr;
376};250};
377 251 
378const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &lower_input,252const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &lower_input,
@@ -384,18 +258,6 @@ const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &
384 }258 }
385 lowering_data.kernel_def = &task_def->kernel();259 lowering_data.kernel_def = &task_def->kernel();
386 lowering_data.session_id = bg::GetSessionId(*lower_input.global_data);260 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- }
399 261 
400 // alloc args262 // alloc args
401 lowering_data.in_num = node->GetInDataNodesAndAnchors().size();263 lowering_data.in_num = node->GetInDataNodesAndAnchors().size();
@@ -408,15 +270,6 @@ const char *PrepareHostAiCpuLowering(const ge::NodePtr &node, const LowerInput &
408 }270 }
409 const auto io_num = lowering_data.in_num + node->GetAllOutDataAnchorsSize();271 const auto io_num = lowering_data.in_num + node->GetAllOutDataAnchorsSize();
410 lowering_data.aicpu_args = bg::BuildHostCCAicpuArg(node, *lowering_data.kernel_def, io_num, lowering_data.session_id);272 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- }
420 return nullptr;273 return nullptr;
421}274}
422 275 
@@ -428,12 +281,6 @@ LowerResult BuildHostAiCpuLoweringResult(const ge::NodePtr &node, const LowerInp
428 281 
429 std::vector<bg::DevMemValueHolderPtr> output_addrs;282 std::vector<bg::DevMemValueHolderPtr> output_addrs;
430 const bg::IoInfo io_info{lower_input.input_addrs, lower_input.input_shapes, output_sizes, output_shapes};283 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- }
437 auto compute_holder =284 auto compute_holder =
438 bg::AicpuHostCompute(node, lowering_data.aicpu_args, io_info, *lower_input.global_data, output_addrs);285 bg::AicpuHostCompute(node, lowering_data.aicpu_args, io_info, *lower_input.global_data, output_addrs);
439 286 
@@ -10,7 +10,6 @@
10 10 
11#include "bg_launch.h"11#include "bg_launch.h"
12#include "bg_ext_info.h"12#include "bg_ext_info.h"
13-#include <algorithm>
14#include <mutex>13#include <mutex>
15#include "framework/common/taskdown_common.h"14#include "framework/common/taskdown_common.h"
16#include "register/kernel_registry.h"15#include "register/kernel_registry.h"
@@ -23,7 +22,6 @@
23#include "graph_builder/bg_condition.h"22#include "graph_builder/bg_condition.h"
24#include "graph/utils/node_utils.h"23#include "graph/utils/node_utils.h"
25#include "exe_graph/lowering/frame_selector.h"24#include "exe_graph/lowering/frame_selector.h"
26-#include "engine/aicpu/kernel/fused_host_cpu_compute.h"
27 25 
28namespace gert {26namespace gert {
29namespace bg {27namespace bg {
@@ -47,7 +45,6 @@ DevMemValueHolderPtr AllocHostCpuOutputMemory(const ge::NodePtr &node, const IoI
47 inputs.insert(inputs.cend(), io_info.input_addrs.cbegin(), io_info.input_addrs.cend());45 inputs.insert(inputs.cend(), io_info.input_addrs.cbegin(), io_info.input_addrs.cend());
48 auto output = DevMemValueHolder::CreateSingleDataOutput("AllocHostCpuOutputMemory", inputs,46 auto output = DevMemValueHolder::CreateSingleDataOutput("AllocHostCpuOutputMemory", inputs,
49 node->GetOpDescBarePtr()->GetStreamId());47 node->GetOpDescBarePtr()->GetStreamId());
50- GE_ASSERT_NOTNULL(output);
51 output->SetPlacement(kOnHost);48 output->SetPlacement(kOnHost);
52 return output;49 return output;
53}50}
@@ -272,46 +269,5 @@ ValueHolderPtr AicpuHostCompute(const ge::NodePtr &node, const AicpuArgs &args,
272 }269 }
273 return compute_holder;270 return compute_holder;
274}271}
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-}
316} // namespace bg272} // namespace bg
317} // namespace gert273} // namespace gert
@@ -52,10 +52,6 @@ ValueHolderPtr AicpuHostExecFuncProcess(const AicpuHostProcFunc &func, const IoI
52 const std::vector<DevMemValueHolderPtr> &output_addrs);52 const std::vector<DevMemValueHolderPtr> &output_addrs);
53ValueHolderPtr AicpuHostCompute(const ge::NodePtr &node, const AicpuArgs &args, const IoInfo &io_info,53ValueHolderPtr 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);
59ValueHolderPtr GetContainerIdHolder(const LowerInput &lower_input);55ValueHolderPtr GetContainerIdHolder(const LowerInput &lower_input);
60} // namespace bg56} // namespace bg
61} // namespace gert57} // namespace gert
@@ -12,8 +12,6 @@
12#include <cstddef>12#include <cstddef>
13#include <iomanip>13#include <iomanip>
14#include <cinttypes>14#include <cinttypes>
15-#include <memory>
16-#include <new>
17#include "aicpu_ext_info_handle.h"15#include "aicpu_ext_info_handle.h"
18#include "graph/error_codes.h"16#include "graph/error_codes.h"
19#include "register/kernel_registry.h"17#include "register/kernel_registry.h"
@@ -31,7 +29,6 @@
31#include "core/debug/kernel_tracing.h"29#include "core/debug/kernel_tracing.h"
32#include "core/executor/multi_thread_topological/executor/schedule/producer/producers/kernel_tags/critical_section_config.h"30#include "core/executor/multi_thread_topological/executor/schedule/producer/producers/kernel_tags/critical_section_config.h"
33#include "aicpu_resource_manager.h"31#include "aicpu_resource_manager.h"
34-#include "fused_host_cpu_compute.h"
35#include "engine/aicpu/graph_builder/bg_aicpu_arg.h"32#include "engine/aicpu/graph_builder/bg_aicpu_arg.h"
36#include "aicpu_args_handler.h"33#include "aicpu_args_handler.h"
37#include "block_op_utils.h"34#include "block_op_utils.h"
@@ -42,7 +39,6 @@
42#include "exe_graph/runtime/gert_tensor_data.h"39#include "exe_graph/runtime/gert_tensor_data.h"
43#include "graph/load/model_manager/model_manager.h"40#include "graph/load/model_manager/model_manager.h"
44#include "aicpu_bin_handler.h"41#include "aicpu_bin_handler.h"
45-#include "exe_graph/runtime/storage_shape.h"
46 42 
47using namespace ge;43using namespace ge;
48 44 
@@ -416,183 +412,6 @@ ge::graphStatus AicpuHostCompute(KernelContext *context) {
416}412}
417REGISTER_KERNEL(AicpuHostCompute).RunFunc(AicpuHostCompute);413REGISTER_KERNEL(AicpuHostCompute).RunFunc(AicpuHostCompute);
418 414 
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- 
596ge::graphStatus AicpuHostExecFunc(KernelContext *context) {415ge::graphStatus AicpuHostExecFunc(KernelContext *context) {
597 const auto input_size = context->GetInputNum();416 const auto input_size = context->GetInputNum();
598 // func取输入的最后一个,因为前面输入个数不固定。417 // func取输入的最后一个,因为前面输入个数不固定。
@@ -9,8 +9,6 @@
9 */9 */
10 10 
11#include "aicpu_resource_manager.h"11#include "aicpu_resource_manager.h"
12-#include <algorithm>
13-#include <cstddef>
14#include "framework/common/debug/ge_log.h"12#include "framework/common/debug/ge_log.h"
15#include "exe_graph/runtime/kernel_context.h"13#include "exe_graph/runtime/kernel_context.h"
16#include "rt_external_kernel.h"14#include "rt_external_kernel.h"
@@ -25,14 +23,6 @@
25#include "mmpa/mmpa_api.h"23#include "mmpa/mmpa_api.h"
26#include "graph/load/model_manager/model_manager.h"24#include "graph/load/model_manager/model_manager.h"
27#include "common/aclrt_malloc_helper.h"25#include "common/aclrt_malloc_helper.h"
28-#include "framework/common/host_cpu_fusion_attr.h"
29- 
30-#if defined(__linux__)
31-#include <cerrno>
32-#include <dlfcn.h>
33-#include <sys/syscall.h>
34-#include <unistd.h>
35-#endif
36 26 
37namespace gert {27namespace gert {
38namespace {28namespace {
@@ -44,78 +34,6 @@ void FreeHbmMem(void *p) {
44 34 
45const std::string kHostCpuLibRelativePathOld = "/op_impl/built-in/host_cpu/libconstant_folding_ops.so";35const std::string kHostCpuLibRelativePathOld = "/op_impl/built-in/host_cpu/libconstant_folding_ops.so";
46const std::string kHostCpuLibRelativePath = "/built-in/op_impl/host_cpu/libconstant_folding_ops.so";36const 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 &register_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-#if defined(__aarch64__)
84- return machine == 183U;
85-#elif defined(__x86_64__)
86- return machine == 62U;
87-#else
88- (void)machine;
89- return true;
90-#endif
91-}
92- 
93-bool ValidateFusedHostCpuRegistration(void *handle, const std::string &register_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-#if defined(__linux__)
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-#endif
119 37 
120ge::graphStatus GetRealPath(std::string &path) {38ge::graphStatus GetRealPath(std::string &path) {
121 const std::string real_path = ge::RealPath(path.c_str());39 const std::string real_path = ge::RealPath(path.c_str());
@@ -154,20 +72,10 @@ AicpuResourceManager &AicpuResourceManager::GetInstance() {
154}72}
155 73 
156AicpuResourceManager::~AicpuResourceManager() {74AicpuResourceManager::~AicpuResourceManager() {
157- // CpuKernelRegister 没有注销接口,其 std::function creator 指向 JIT so。这里必须先让基础 HostCPU
158- // 库在 dlclose 时销毁 registry,再由进程回收仍映射的 JIT so,不能提前 dlclose 形成悬空 creator。
159 if (so_handle_ != nullptr) {75 if (so_handle_ != nullptr) {
160 (void)mmDlclose(so_handle_);76 (void)mmDlclose(so_handle_);
161 so_handle_ = nullptr;77 so_handle_ = nullptr;
162 }78 }
163-#if defined(__linux__)
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-#endif
171}79}
172 80 
173ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() {81ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() {
@@ -210,174 +118,6 @@ ge::graphStatus AicpuResourceManager::LoadConstantFoldingLib() {
210 return ge::GRAPH_SUCCESS;118 return ge::GRAPH_SUCCESS;
211}119}
212 120 
213-ge::graphStatus AicpuResourceManager::TryReuseFusedHostCpuSo(const std::string &register_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 &register_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-#if !defined(__linux__)
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-#else
272- return LoadNewFusedHostCpuSo(register_name, so_data, so_size, so_hash);
273-#endif
274-}
275- 
276-#if defined(__linux__)
277-ge::graphStatus AicpuResourceManager::LoadNewFusedHostCpuSo(const std::string &register_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 &register_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-#endif
344- 
345-FusedHostCpuKernelFunctions AicpuResourceManager::GetFusedHostCpuKernelFunctions(const std::string &register_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 &register_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- 
381std::function<uint32_t(void *)> AicpuResourceManager::GetRunCpuKernel() const {121std::function<uint32_t(void *)> AicpuResourceManager::GetRunCpuKernel() const {
382 return run_cpu_kernel_;122 return run_cpu_kernel_;
383}123}
@@ -456,14 +196,6 @@ ge::graphStatus EnsureCreateTfSession(KernelContext *context) {
456}196}
457REGISTER_KERNEL(EnsureCreateTfSession).RunFunc(EnsureCreateTfSession);197REGISTER_KERNEL(EnsureCreateTfSession).RunFunc(EnsureCreateTfSession);
458 198 
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- 
467ge::graphStatus CreateStepId(KernelContext *context) {199ge::graphStatus CreateStepId(KernelContext *context) {
468 auto step_id = context->GetOutputPointer<void *>(0U);200 auto step_id = context->GetOutputPointer<void *>(0U);
469 auto iteration = context->GetOutputPointer<int64_t>(1U);201 auto iteration = context->GetOutputPointer<int64_t>(1U);
@@ -11,12 +11,8 @@
11#ifndef AIR_CXX_RUNTIME_V2_KERNEL_LAUNCH_KERNEL_AICPU_AICPU_RESOURCE_MANAGER_H_11#ifndef AIR_CXX_RUNTIME_V2_KERNEL_LAUNCH_KERNEL_AICPU_AICPU_RESOURCE_MANAGER_H_
12#define AIR_CXX_RUNTIME_V2_KERNEL_LAUNCH_KERNEL_AICPU_AICPU_RESOURCE_MANAGER_H_12#define AIR_CXX_RUNTIME_V2_KERNEL_LAUNCH_KERNEL_AICPU_AICPU_RESOURCE_MANAGER_H_
13 13 
14-#include <cstddef>
15-#include <cstdint>
16#include <mutex>14#include <mutex>
17#include <deque>15#include <deque>
18-#include <map>
19-#include <vector>
20#include "ge/ge_api_error_codes.h"16#include "ge/ge_api_error_codes.h"
21#include "exe_graph/runtime/tensor_data.h"17#include "exe_graph/runtime/tensor_data.h"
22#include "graph/op_desc.h"18#include "graph/op_desc.h"
@@ -30,15 +26,6 @@
30namespace gert {26namespace gert {
31 27 
32using AicpuHostProcFunc = ge::graphStatus (*)(KernelContext *);28using 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-};
42 29 
43class AicpuResourceManager {30class AicpuResourceManager {
44 public:31 public:
@@ -46,9 +33,6 @@ class AicpuResourceManager {
46 ~AicpuResourceManager();33 ~AicpuResourceManager();
47 34 
48 ge::graphStatus LoadConstantFoldingLib();35 ge::graphStatus LoadConstantFoldingLib();
49- ge::graphStatus LoadFusedHostCpuSo(const std::string &register_name, const uint8_t *so_data, size_t so_size);
50- ge::graphStatus ReleaseFusedHostCpuSo(const std::string &register_name);
51- FusedHostCpuKernelFunctions GetFusedHostCpuKernelFunctions(const std::string &register_name);
52 std::function<uint32_t(void *)> GetRunCpuKernel() const;36 std::function<uint32_t(void *)> GetRunCpuKernel() const;
53 std::function<AicpuHostProcFunc(std::string)> GetAicpuHostFindFunc() const;37 std::function<AicpuHostProcFunc(std::string)> GetAicpuHostFindFunc() const;
54 38 
@@ -68,12 +52,6 @@ class AicpuResourceManager {
68 ge::graphStatus HasLoadedCustAicpuSo(const std::string &so_name, bool &loaded);52 ge::graphStatus HasLoadedCustAicpuSo(const std::string &so_name, bool &loaded);
69 53 
70 private:54 private:
71- ge::graphStatus TryReuseFusedHostCpuSo(const std::string &register_name, const uint8_t *so_data, size_t so_size,
72- uint64_t so_hash, bool &handled);
73- ge::graphStatus LoadNewFusedHostCpuSo(const std::string &register_name, const uint8_t *so_data, size_t so_size,
74- uint64_t so_hash);
75- ge::graphStatus OpenFusedHostCpuSo(const std::string &register_name, const uint8_t *so_data, size_t so_size,
76- void *&handle, int &fd, FusedHostCpuKernelFunctions &kernel_funcs);
77 ge::graphStatus CheckOrCreateHandle(const std::string &op_name, const rtStream_t stream,55 ge::graphStatus CheckOrCreateHandle(const std::string &op_name, const rtStream_t stream,
78 const GertTensorData *handle_data);56 const GertTensorData *handle_data);
79 AicpuResourceManager() = default;57 AicpuResourceManager() = default;
@@ -83,18 +61,6 @@ class AicpuResourceManager {
83 std::function<uint32_t(void *)> run_cpu_kernel_ = nullptr;61 std::function<uint32_t(void *)> run_cpu_kernel_ = nullptr;
84 std::function<AicpuHostProcFunc(std::string)> aicpu_host_find_func_ = nullptr;62 std::function<AicpuHostProcFunc(std::string)> aicpu_host_find_func_ = nullptr;
85 void *so_handle_ = nullptr;63 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_;
98 64 
99 std::map<uint64_t, std::deque<GertTensorData>> tensors_;65 std::map<uint64_t, std::deque<GertTensorData>> tensors_;
100 std::map<std::string, uint64_t> handles_;66 std::map<std::string, uint64_t> handles_;