已合并
revert: 回退ordinary AICPU常量折叠迁移 #5239
revert: 回退ordinary AICPU常量折叠迁移 #5239
已合并
pantong创建于 26 天前
共 18 个文件变更+1410-39
@@ -534,7 +534,7 @@ elseif (BUILD_OPEN_PROJECT OR ENABLE_OPEN_SRC)
534 if (NOT MDC_COMPILE_RUNTIME)534 if (NOT MDC_COMPILE_RUNTIME)
535 add_custom_target(ge-compiler)535 add_custom_target(ge-compiler)
536 add_dependencies(ge-compiler parser_common aicore_utils fusion_pass op_compile_adapter aicpu_engine_common fmk_parser ge_compiler536 add_dependencies(ge-compiler parser_common aicore_utils fusion_pass op_compile_adapter aicpu_engine_common fmk_parser ge_compiler
537- fmk_onnx_parser opskernel ge_runner slice llm_engine jit_exe _caffe_parser flow_graph aihac_autofusion537+ fmk_onnx_parser opskernel ge_runner slice aicpu_const_folding llm_engine jit_exe _caffe_parser flow_graph aihac_autofusion
538 dflow_runner eager_style_graph_builder_base eager_style_graph_builder_base_static gen_esb538 dflow_runner eager_style_graph_builder_base eager_style_graph_builder_base_static gen_esb
539 aihac_symbolizer ge_python llm_datadist_python_v1 dataflow_python ge_python_pass_bridge539 aihac_symbolizer ge_python llm_datadist_python_v1 dataflow_python ge_python_pass_bridge
540 ge_python_custom_op_bridge func2graph)540 ge_python_custom_op_bridge func2graph)
@@ -24,7 +24,7 @@ namespace ge {
24namespace {24namespace {
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";
27-const std::string kOpConstantFoldingName = "libopconstant_folding.so";27+const std::string kAicpuConstFoldingName = "libaicpu_const_folding.so";
28constexpr char kAicpuHostFindFunc[] = "AicpuHostFindFunc";28constexpr 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) {
@@ -110,13 +110,28 @@ ge::Status HostCpuEngine::Initialize(const std::string &path_base) {
110 (void)LoadLib(constant_folding_name);110 (void)LoadLib(constant_folding_name);
111 }111 }
112 112 
113+ // libops_host_cpu.so 中除 AICPU 注册的常量折叠算子之外, 还包含其他
114+ // 通过 REGISTER_HOST_CPU_OP_BUILDER 注册的常量折叠算子, 必须先 dlopen
115+ // 让其 file-scope 静态注册先写入 op_type 路由, 但此时不调用其 Initialize,
116+ // 给后续的 libaicpu_const_folding.so Initialize 留出"后写覆盖"的机会
113 std::string ops_host_cpu_name = lib_dir + "/" + kOpsHostCpuName;117 std::string ops_host_cpu_name = lib_dir + "/" + kOpsHostCpuName;
118+ void *ops_host_cpu_handle = nullptr;
114 if (GetEngineRealPath(ops_host_cpu_name) == SUCCESS) {119 if (GetEngineRealPath(ops_host_cpu_name) == SUCCESS) {
115- (void)LoadLib(ops_host_cpu_name, true);120+ ops_host_cpu_handle = DlopenLib(ops_host_cpu_name);
121+ if (ops_host_cpu_handle != nullptr) {
122+ GELOGI("Lib: %s has been opened (initialize deferred)", ops_host_cpu_name.c_str());
123+ (void)lib_handles_.emplace_back(ops_host_cpu_handle);
124+ }
116 }125 }
117 126 
118- // Load the opbase ordinary constant-folding router after the fused HostCPU library is initialized.127+ // 后加载 libaicpu_const_folding.so 并执行 Initialize: 成功则 V2 wrapper 工厂
119- (void)LoadOpConstantFoldingLib(kOpConstantFoldingName, lib_dir);128+ // 通过 last-write-wins 语义覆盖 libops_host_cpu.so 中同名 op_type 的注册项
129+ // AICPU 路径不可用时, 回退执行 libops_host_cpu.so 的 Initialize, 注册 V1 wrapper
130+ // 兜底, 保证常量折叠链路可用
131+ const bool aicpu_init_ok = (LoadLib(kAicpuConstFoldingName, true) == SUCCESS);
132+ if (!aicpu_init_ok && ops_host_cpu_handle != nullptr) {
133+ (void)InvokeLibInitialize(ops_host_cpu_handle, ops_host_cpu_name);
134+ }
120 135 
121 initialized_ = true;136 initialized_ = true;
122 return SUCCESS;137 return SUCCESS;
@@ -248,13 +263,9 @@ Status HostCpuEngine::Run(const NodePtr &node, HostCpuOp &kernel, const std::vec
248 return SUCCESS;263 return SUCCESS;
249}264}
250 265 
251-void *HostCpuEngine::DlopenLib(const std::string &lib_path, bool global) const {266+void *HostCpuEngine::DlopenLib(const std::string &lib_path) const {
252 GELOGI("To invoke dlopen on lib: %s", lib_path.c_str());267 GELOGI("To invoke dlopen on lib: %s", lib_path.c_str());
253- // RTLD_LOCAL is the default when RTLD_GLOBAL is absent.268+ constexpr uint32_t open_flag = static_cast<uint32_t>(MMPA_RTLD_NOW) | static_cast<uint32_t>(MMPA_RTLD_GLOBAL);
254- uint32_t open_flag = static_cast<uint32_t>(MMPA_RTLD_NOW);
255- if (global) {
256- open_flag |= static_cast<uint32_t>(MMPA_RTLD_GLOBAL);
257- }
258 auto handle = mmDlopen(lib_path.c_str(), static_cast<int32_t>(open_flag));269 auto handle = mmDlopen(lib_path.c_str(), static_cast<int32_t>(open_flag));
259 if (handle == nullptr) {270 if (handle == nullptr) {
260 const char_t *error = mmDlerror();271 const char_t *error = mmDlerror();
@@ -306,30 +317,6 @@ Status HostCpuEngine::LoadLib(const std::string &lib_path, bool invoke_init) {
306 return SUCCESS;317 return SUCCESS;
307}318}
308 319 
309-Status HostCpuEngine::LoadOpConstantFoldingLib(const std::string &lib_path, const std::string &host_cpu_dir) {
310- void *handle = DlopenLib(lib_path, false);
311- if (handle == nullptr) {
312- return INTERNAL_ERROR;
313- }
314- using InitFunc = int32_t (*)(const char *);
315- const auto initialize = reinterpret_cast<InitFunc>(mmDlsym(handle, "ConstantFoldingInitialize"));
316- if (initialize == nullptr) {
317- const char_t *reason = mmDlerror();
318- reason = (reason == nullptr) ? "" : reason;
319- GELOGW("[Find][ConstantFoldingInitialize] symbol not found in lib: %s, reason = %s", lib_path.c_str(), reason);
320- (void)mmDlclose(handle);
321- return INTERNAL_ERROR;
322- }
323- if (initialize(host_cpu_dir.c_str()) != 0) {
324- GELOGW("[Invoke][ConstantFoldingInitialize] failed. path = %s", lib_path.c_str());
325- (void)mmDlclose(handle);
326- return INTERNAL_ERROR;
327- }
328- GELOGI("Lib: %s has been opened", lib_path.c_str());
329- (void)lib_handles_.emplace_back(handle);
330- return SUCCESS;
331-}
332- 
333Status HostCpuEngine::GetEngineRealPath(std::string &path) {320Status HostCpuEngine::GetEngineRealPath(std::string &path) {
334 const std::string real_path = RealPath(path.c_str());321 const std::string real_path = RealPath(path.c_str());
335 if (real_path.empty()) {322 if (real_path.empty()) {
@@ -50,14 +50,12 @@ class HostCpuEngine {
50 50 
51 HostCpuEngine() = default;51 HostCpuEngine() = default;
52 52 
53- void *DlopenLib(const std::string &lib_path, bool global = true) const;53+ void *DlopenLib(const std::string &lib_path) const;
54 54 
55 Status InvokeLibInitialize(void *handle, const std::string &lib_path) const;55 Status InvokeLibInitialize(void *handle, const std::string &lib_path) const;
56 56 
57 Status LoadLib(const std::string &lib_path, bool invoke_init = false);57 Status LoadLib(const std::string &lib_path, bool invoke_init = false);
58 58 
59- Status LoadOpConstantFoldingLib(const std::string &lib_path, const std::string &host_cpu_dir);
60- 
61 static Status GetEngineRealPath(std::string &path);59 static Status GetEngineRealPath(std::string &path);
62 60 
63 static Status PrepareInputs(const ConstOpDescPtr &op_desc, const std::vector<ConstGeTensorPtr> &inputs,61 static Status PrepareInputs(const ConstOpDescPtr &op_desc, const std::vector<ConstGeTensorPtr> &inputs,
@@ -76,7 +76,7 @@ if("ge-compiler" IN_LIST BUILD_COMPONENT)
76 install_public_packages(ge-compiler)76 install_public_packages(ge-compiler)
77 if(NOT MDC_COMPILE_RUNTIME)77 if(NOT MDC_COMPILE_RUNTIME)
78 install(TARGETS parser_common aicore_utils fusion_pass op_compile_adapter aicpu_engine_common fmk_parser ge_compiler fmk_onnx_parser opskernel ge_runner78 install(TARGETS parser_common aicore_utils fusion_pass op_compile_adapter aicpu_engine_common fmk_parser ge_compiler fmk_onnx_parser opskernel ge_runner
79- slice llm_engine jit_exe _caffe_parser func2graph flow_graph aihac_autofusion dflow_runner eager_style_graph_builder_base79+ slice aicpu_const_folding llm_engine jit_exe _caffe_parser func2graph flow_graph aihac_autofusion dflow_runner eager_style_graph_builder_base
80 eager_style_graph_builder_base_static ge_runner_v2 aihac_symbolizer compress compressweight80 eager_style_graph_builder_base_static ge_runner_v2 aihac_symbolizer compress compressweight
81 hcom_gradient_split_tune hcom_graph_adaptor acl_op_compiler81 hcom_gradient_split_tune hcom_graph_adaptor acl_op_compiler
82 LIBRARY DESTINATION ${ARCH_LINUX_PATH}/lib64 COMPONENT ge-compiler82 LIBRARY DESTINATION ${ARCH_LINUX_PATH}/lib64 COMPONENT ge-compiler
@@ -12,6 +12,8 @@ set(proto_src_files
12 ${METADEF_PROTO_DIR}/task.proto12 ${METADEF_PROTO_DIR}/task.proto
13)13)
14 14 
15+add_subdirectory(constant_folding_stub)
16+ 
15generate_cann_protobuf(aicpu PROTO_SRCS PROTO_HDRS ${proto_src_files})17generate_cann_protobuf(aicpu PROTO_SRCS PROTO_HDRS ${proto_src_files})
16 18 
17set(local_aicpu_src_files19set(local_aicpu_src_files
@@ -37,6 +39,11 @@ set(local_hostcpu_builder_src_files
37 ${PROTO_HDRS}39 ${PROTO_HDRS}
38)40)
39 41 
42+set(local_aicpu_const_folding_src_files
43+ ${CMAKE_CURRENT_SOURCE_DIR}/aicpu_const_folding/folding.cc
44+ ${CMAKE_CURRENT_SOURCE_DIR}/aicpu_const_folding/host_cpu_kernel_wrapper.cpp
45+)
46+ 
40set(local_lib_inc_path47set(local_lib_inc_path
41 ${CMAKE_CURRENT_SOURCE_DIR}48 ${CMAKE_CURRENT_SOURCE_DIR}
42 ${AIR_CODE_DIR}/compiler/engines/cpu_engine49 ${AIR_CODE_DIR}/compiler/engines/cpu_engine
@@ -57,6 +64,10 @@ add_library(host_cpu_opskernel_builder SHARED
57 ${local_hostcpu_builder_src_files}64 ${local_hostcpu_builder_src_files}
58)65)
59 66 
67+add_library(aicpu_const_folding SHARED
68+ ${local_aicpu_const_folding_src_files}
69+)
70+ 
60target_include_directories(aicpu_ascend_engine PRIVATE71target_include_directories(aicpu_ascend_engine PRIVATE
61 ${local_lib_inc_path}72 ${local_lib_inc_path}
62)73)
@@ -69,6 +80,28 @@ target_include_directories(host_cpu_opskernel_builder PRIVATE
69 ${local_lib_inc_path}80 ${local_lib_inc_path}
70)81)
71 82 
83+if (BUILD_OPEN_PROJECT OR ENABLE_OPEN_SRC)
84+ target_include_directories(aicpu_const_folding PRIVATE
85+ ${CMAKE_CURRENT_SOURCE_DIR}
86+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine
87+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine/common
88+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine/aicpu_const_folding
89+ ${CMAKE_BINARY_DIR}/proto/aicpu
90+ ${CMAKE_BINARY_DIR}/proto/aicpu/proto
91+ )
92+else ()
93+ target_include_directories(aicpu_const_folding PRIVATE
94+ ${CMAKE_CURRENT_SOURCE_DIR}
95+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine
96+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine/common
97+ ${AIR_CODE_DIR}/compiler/engines/cpu_engine/aicpu_const_folding
98+ ${CMAKE_BINARY_DIR}/proto/aicpu
99+ ${CMAKE_BINARY_DIR}/proto/aicpu/proto
100+ ${TOP_DIR}/inc/aicpu/cpu_kernels
101+ ${TOP_DIR}/inc/external/aicpu
102+ )
103+endif ()
104+ 
72target_compile_options(aicpu_ascend_engine PRIVATE105target_compile_options(aicpu_ascend_engine PRIVATE
73 -Wno-deprecated-declarations106 -Wno-deprecated-declarations
74 -fno-common107 -fno-common
@@ -90,6 +123,14 @@ target_compile_options(host_cpu_opskernel_builder PRIVATE
90 -Werror123 -Werror
91)124)
92 125 
126+target_compile_options(aicpu_const_folding PRIVATE
127+ -ftrapv
128+ -fstack-protector-all
129+ -fvisibility-inlines-hidden
130+ -fvisibility=hidden
131+ -Wno-deprecated-declarations
132+)
133+ 
93target_compile_definitions(aicpu_ascend_engine PRIVATE134target_compile_definitions(aicpu_ascend_engine PRIVATE
94 AICPU_PLUGIN135 AICPU_PLUGIN
95 google=ascend_private136 google=ascend_private
@@ -105,6 +146,18 @@ target_compile_definitions(host_cpu_opskernel_builder PRIVATE
105 google=ascend_private146 google=ascend_private
106)147)
107 148 
149+target_compile_definitions(aicpu_const_folding PRIVATE
150+ google=ascend_private
151+ LOG_CPP
152+ HOST_VISIBILITY
153+)
154+ 
155+target_link_options(aicpu_const_folding PRIVATE
156+ -Wl,-z,relro,-z,now
157+ -Wl,-Bsymbolic -Wl,--exclude-libs,ALL
158+ $<$<NOT:$<STREQUAL:${RESERVED_SYMBOL},true>>:-s>
159+)
160+ 
108target_link_libraries(aicpu_ascend_engine PRIVATE161target_link_libraries(aicpu_ascend_engine PRIVATE
109 ge_intf_pub162 ge_intf_pub
110 msprof_headers163 msprof_headers
@@ -175,6 +228,44 @@ target_link_libraries(host_cpu_opskernel_builder PRIVATE
175 -ldl228 -ldl
176)229)
177 230 
231+if (BUILD_OPEN_PROJECT OR ENABLE_OPEN_SRC)
232+ target_link_libraries(aicpu_const_folding PRIVATE
233+ ge_intf_pub
234+ $<$<TARGET_EXISTS:aicpu_headers>:aicpu_headers>
235+ air_headers
236+ mmpa_headers
237+ metadef_headers
238+ runtime_headers
239+ c_sec_headers
240+ -Wl,--no-as-needed
241+ constant_folding_ops_stub
242+ slog_headers
243+ error_manager
244+ ascend_protobuf
245+ aicpu_engine_common
246+ mmpa
247+ json
248+ acl_rt
249+ -Wl,--as-needed
250+ )
251+else ()
252+ target_link_libraries(aicpu_const_folding PRIVATE
253+ ge_intf_pub
254+ air_headers
255+ mmpa_headers
256+ -Wl,--no-as-needed
257+ constant_folding_ops_stub
258+ slog_headers
259+ error_manager
260+ ascend_protobuf
261+ aicpu_engine_common
262+ mmpa
263+ json
264+ acl_rt
265+ -Wl,--as-needed
266+ )
267+endif ()
268+ 
178#####改名称用的,因为一个cmake不能2个相同的名字的链接so 可执行程序 等269#####改名称用的,因为一个cmake不能2个相同的名字的链接so 可执行程序 等
179 270 
180install(TARGETS aicpu_ascend_engine ${INSTALL_OPTIONAL}271install(TARGETS aicpu_ascend_engine ${INSTALL_OPTIONAL}
@@ -191,3 +282,8 @@ install(TARGETS host_cpu_opskernel_builder ${INSTALL_OPTIONAL}
191 EXPORT host_cpu_opskernel_builder-targets282 EXPORT host_cpu_opskernel_builder-targets
192 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}283 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
193)284)
285+ 
286+install(TARGETS aicpu_const_folding ${INSTALL_OPTIONAL}
287+ EXPORT aicpu_const_folding-targets
288+ LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
289+)
@@ -0,0 +1,684 @@
1+/**
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+#include "folding.h"
17+ 
18+#include <vector>
19+#include <set>
20+#include <string>
21+#include <unordered_map>
22+#include <dirent.h>
23+#include <dlfcn.h>
24+#include <cstring>
25+#include "cpu_kernel_register.h"
26+#include "cpu_kernel.h"
27+#include "cpu_context.h"
28+#include "proto/aicpu/cpu_attr.pb.h"
29+#include "proto/aicpu/cpu_node_def.pb.h"
30+#include "proto/aicpu/cpu_tensor.pb.h"
31+#include "proto/aicpu/cpu_tensor_shape.pb.h"
32+#include "util/aicpu_log.h"
33+#include "graph/types.h"
34+#include "mmpa/mmpa_api.h"
35+ 
36+namespace {
37+const char *const kVtString = "VT_STRING";
38+const char *const kVtListString = "VT_LIST_STRING";
39+const char *const kVtFloat = "VT_FLOAT";
40+const char *const kVtListFloat = "VT_LIST_FLOAT";
41+const char *const kVtInt = "VT_INT";
42+const char *const kVtListInt = "VT_LIST_INT";
43+const char *const kVtListListInt = "VT_LIST_LIST_INT";
44+const char *const kVtBool = "VT_BOOL";
45+const char *const kVtListBool = "VT_LIST_BOOL";
46+const char *const kVtDataType = "VT_DATA_TYPE";
47+const char *const kVtListDataType = "VT_LIST_DATA_TYPE";
48+const char *const kVtTensor = "VT_TENSOR";
49+const char *const kVtListTensor = "VT_LIST_TENSOR";
50+const char kPathSeparator = '/';
51+const char *const kConstantFoldingSoPrefix = "libopconstant_folding_";
52+const char *const kConstantFoldingSoSuffix = ".so";
53+const char *const kExcludedConstantFoldingSo = "libconstant_folding_ops.so";
54+const char *const kSymGetAllRegisteredOpTypesV2 = "GetAllRegisteredOpTypesV2";
55+const char *const kSymIsRegisteredV2 = "IsRegisteredV2";
56+const char *const kSymRunCpuKernelV2 = "RunCpuKernelV2";
57+ 
58+using AttrValueMap = google::protobuf::Map<string, aicpuops::AttrValue>;
59+ 
60+using GetAllRegisteredOpTypesV2Fn = std::vector<std::string> (*)();
61+using IsRegisteredV2Fn = bool (*)(const std::string &);
62+using RunCpuKernelV2Fn = uint32_t (*)(aicpu::CpuKernelContext &);
63+ 
64+struct V2ModuleBinding {
65+ void *handle = nullptr;
66+ GetAllRegisteredOpTypesV2Fn get_all_op_types = nullptr;
67+ IsRegisteredV2Fn is_registered = nullptr;
68+ RunCpuKernelV2Fn run_cpu_kernel = nullptr;
69+ std::string so_name;
70+};
71+ 
72+std::vector<V2ModuleBinding> g_v2_bindings;
73+// op_type->binding反向索引, Init阶段一次性构建, 运行期只读。
74+std::unordered_map<std::string, const V2ModuleBinding *> g_v2_op_index;
75+ 
76+void ConvertGeToAicpuTensor(const ge::GeTensorDesc &tensor_desc, const std::string &tensor_name,
77+ const ge::Tensor &ge_tensor, aicpuops::Tensor *aicpu_tensor) {
78+ aicpu_tensor->set_name(tensor_name);
79+ aicpu_tensor->set_tensor_type(tensor_desc.GetDataType());
80+ aicpu_tensor->set_data_ptr(static_cast<uint64_t>(reinterpret_cast<intptr_t>(ge_tensor.GetData())));
81+ aicpu_tensor->set_data_size(static_cast<uint64_t>(ge_tensor.GetSize()));
82+ auto shape = aicpu_tensor->mutable_tensor_shape();
83+ if (shape != nullptr) {
84+ shape->clear_dim();
85+ std::vector<int64_t> dims = tensor_desc.GetShape().GetDims();
86+ for (size_t i = 0; i < dims.size(); i++) {
87+ aicpuops::TensorShape_Dim *aicpu_dims = shape->add_dim();
88+ if (aicpu_dims != nullptr) {
89+ aicpu_dims->set_size(dims[i]);
90+ }
91+ }
92+ shape->set_data_format(static_cast<ge::Format>(tensor_desc.GetFormat()));
93+ }
94+ AICPUE_LOGI("Op set tensor[%s], tensor info[type:%d, data:%p, size:%llu].", tensor_name.c_str(),
95+ static_cast<int>(tensor_desc.GetDataType()), ge_tensor.GetData(), ge_tensor.GetSize());
96+}
97+ 
98+int32_t AddStringAttrToNodeDef(const ge::Operator &op, const char *name, [[maybe_unused]] aicpuops::NodeDef node_def,
99+ aicpuops::AttrValue &attr_value) {
100+ std::string s;
@@ -0,0 +1,34 @@
1+/**
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ *
6+ * you may not use this file except in compliance with the License.
7+ * You may obtain a copy of the License at
8+ *
9+ * http://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS,
13+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ * See the License for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+#ifndef GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
18+#define GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
19+ 
20+#include <cstdint>
21+#include <map>
22+#include <string>
23+ 
24+#include "graph/utils/op_desc_utils.h"
25+#include "graph_metadef/register/graph_register.h"
26+ 
27+extern "C" {
28+__attribute__((visibility("default"))) int32_t InitCpuConstantFoldingNew(ge::HostCpuOp *(*create_fn)());
29+ 
30+__attribute__((visibility("default"))) int32_t
31+CpuConstantFoldingComputeNew(const ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,
32+ std::map<std::string, ge::Tensor> outputs);
33+}
34+#endif // GE_GE_LOCAL_ENGINE_ENGINE_AICPU_FOLDING_FOLDING_H_
@@ -0,0 +1,59 @@
1+/**
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ 
17+#include "host_cpu_kernel_wrapper.h"
18+#include <unistd.h>
19+#include <string>
20+#include "folding.h"
21+#include "register/host_cpu_context.h"
22+#include "graph/utils/op_desc_utils.h"
23+#include "util/aicpu_log.h"
24+ 
25+extern "C" {
26+FMK_FUNC_HOST_VISIBILITY ge::graphStatus Initialize(const ge::HostCpuContext &ctx) {
27+ (void)ctx;
28+ AICPUE_LOGI("Enter host CPU kernel wrapper initialize");
29+ int32_t ret =
30+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuKernelWrapperOpV2(); });
31+ if (ret != 0) {
32+ AICPUE_LOGW("InitCpuConstantFoldingNew run failed, ret: %d", ret);
33+ return ge::GRAPH_FAILED;
34+ }
35+ 
36+ AICPUE_LOGI("Host CPU kernel wrapper initialize successfully");
37+ return ge::GRAPH_SUCCESS;
38+}
39+}
40+ 
41+namespace ge {
42+HostCpuKernelWrapperOpV2::HostCpuKernelWrapperOpV2() = default;
43+ 
44+graphStatus HostCpuKernelWrapperOpV2::Compute(ge::Operator &op, const std::map<std::string, const ge::Tensor> &inputs,
45+ std::map<std::string, ge::Tensor> &outputs) {
46+ AICPUE_LOGI("Enter host CPU kernel wrapper compute");
47+ 
48+ int32_t ret = CpuConstantFoldingComputeNew(op, inputs, outputs);
49+ if (ret != 0) {
50+ AICPUE_LOGW("CpuConstantFoldingComputeNew run failed, ret: %d", ret);
51+ return ge::GRAPH_FAILED;
52+ }
53+ 
54+ AICPUE_LOGI("Host CPU kernel wrapper compute successfully");
55+ return ge::GRAPH_SUCCESS;
56+}
57+ 
58+REGISTER_HOST_CPU_OP_BUILDER("HostCpuKernelWrapperOpV2", ge::HostCpuKernelWrapperOpV2);
59+} // namespace ge
@@ -0,0 +1,30 @@
1+/**
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+#ifndef GE_GE_LOCAL_ENGINE_ENGINE_HOST_CPU_KERNEL_WRAPPER_H_
17+#define GE_GE_LOCAL_ENGINE_ENGINE_HOST_CPU_KERNEL_WRAPPER_H_
18+ 
19+#include "register/graph_register.h"
20+ 
21+namespace ge {
22+class HostCpuKernelWrapperOpV2 : public HostCpuOp {
23+ public:
24+ HostCpuKernelWrapperOpV2();
25+ ~HostCpuKernelWrapperOpV2() override = default;
26+ graphStatus Compute(Operator &op, const std::map<std::string, const ge::Tensor> &inputs,
27+ std::map<std::string, ge::Tensor> &outputs) override;
28+};
29+} // namespace ge
30+#endif // GE_GE_LOCAL_ENGINE_ENGINE_HOST_CPU_KERNEL_WRAPPER_H_
@@ -0,0 +1,25 @@
1+# -----------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+# CANN Open Software License Agreement Version 2.0 (the "License").
5+# Please refer to the License for details. You may not use this file except in compliance with the License.
6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+# See LICENSE in the root of the software repository for the full text of the License.
9+# -----------------------------------------------------------------------------------------------------------
10+ 
11+cmake_minimum_required(VERSION 3.16)
12+ 
13+add_library(constant_folding_ops_stub SHARED
14+ constant_folding_ops_stub.cpp
15+)
16+ 
17+target_include_directories(constant_folding_ops_stub PRIVATE
18+ ${CMAKE_CURRENT_SOURCE_DIR}
19+)
20+ 
21+set_target_properties(constant_folding_ops_stub PROPERTIES
22+ OUTPUT_NAME "constant_folding_ops"
23+)
24+ 
25+target_link_libraries(constant_folding_ops_stub PRIVATE $<BUILD_INTERFACE:ge_intf_pub>)
@@ -0,0 +1,35 @@
1+/**
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * @file constant_folding_ops_stub.cpp
9+ * @brief Stub library for constant_folding_ops (used only at build time).
10+ *
11+ * This file intentionally provides **no real implementations**.
12+ * It only exists so that the AIR repository can be built independently
13+ * without depending on the real constant_folding_ops.so produced by OPP.
14+ *
15+ * At runtime:
16+ * ✅ The real libconstant_folding_ops.so (from OPP) will be loaded first.
17+ * ✅ This stub library will NOT be used.
18+ *
19+ * If this stub is accidentally loaded (extremely unlikely):
20+ * ✅ It still won't crash, because it exports zero symbols.
21+ *
22+ * This file is safe, minimal, and production-friendly.
23+ */
24+ 
25+namespace aicpu_stub {
26+// --------------------------------------------------------------
27+// Optional: provide a weak dummy symbol as a safety fallback
28+// --------------------------------------------------------------
29+// If your linker prefers at least one exported symbol to build a shared lib,
30+// this dummy weak function will satisfy it.
31+// If not needed, it will never be used.
32+// --------------------------------------------------------------
33+__attribute__((weak)) void constant_folding_ops_stub_marker() {}
34+ 
35+} // namespace aicpu_stub
@@ -41,6 +41,7 @@
41 <file value="libeager_style_graph_builder_base_static.a" file_type="static"/>41 <file value="libeager_style_graph_builder_base_static.a" file_type="static"/>
42 <file value="libllm_engine.so" file_type="shared"/>42 <file value="libllm_engine.so" file_type="shared"/>
43 <file value="libslice.so" file_type="shared"/>43 <file value="libslice.so" file_type="shared"/>
44+ <file value="libaicpu_const_folding.so" file_type="shared"/>
44 <file value="libengine.so" file_type="shared" dst_path="lib64/plugin/nnengine" install_path="$(TARGET_ENV)/lib64/plugin/nnengine"/>45 <file value="libengine.so" file_type="shared" dst_path="lib64/plugin/nnengine" install_path="$(TARGET_ENV)/lib64/plugin/nnengine"/>
45 <file value="libhost_cpu_engine.so" file_type="shared" dst_path="lib64/plugin/opskernel" install_path="$(TARGET_ENV)/lib64/plugin/opskernel"/>46 <file value="libhost_cpu_engine.so" file_type="shared" dst_path="lib64/plugin/opskernel" install_path="$(TARGET_ENV)/lib64/plugin/opskernel"/>
46 <file value="libaicpu_tf_engine.so" file_type="shared" dst_path="lib64/plugin/opskernel" install_path="$(TARGET_ENV)/lib64/plugin/opskernel"/>47 <file value="libaicpu_tf_engine.so" file_type="shared" dst_path="lib64/plugin/opskernel" install_path="$(TARGET_ENV)/lib64/plugin/opskernel"/>
@@ -126,6 +126,7 @@ set(cpu_engine_src_files
126 ${cpueng_src_path}/cpu_engine/aicpu_engine/kernel_builder/aicpu_ascend_ops_kernel_builder.cpp126 ${cpueng_src_path}/cpu_engine/aicpu_engine/kernel_builder/aicpu_ascend_ops_kernel_builder.cpp
127 ${cpueng_src_path}/cpu_engine/common/kernel_builder/cpu_kernel_builder.cpp127 ${cpueng_src_path}/cpu_engine/common/kernel_builder/cpu_kernel_builder.cpp
128 ${cpueng_src_path}/cpu_engine/common/optimizer/cpu_optimizer.cpp128 ${cpueng_src_path}/cpu_engine/common/optimizer/cpu_optimizer.cpp
129+ ${cpueng_src_path}/cpu_engine/aicpu_const_folding/folding.cc
129)130)
130 131 
131set(engine_common_src_test_files st_main.cpp)132set(engine_common_src_test_files st_main.cpp)
@@ -153,6 +154,7 @@ else ()
153 ${CMAKE_BINARY_DIR}/proto/aicpu154 ${CMAKE_BINARY_DIR}/proto/aicpu
154 ${CMAKE_BINARY_DIR}/proto/aicpu/proto155 ${CMAKE_BINARY_DIR}/proto/aicpu/proto
155 ${METADEF_DIR}/inc156 ${METADEF_DIR}/inc
157+ ${TOP_DIR}/inc/aicpu/cpu_kernels
156 ${TOP_DIR}/inc/external/aicpu158 ${TOP_DIR}/inc/external/aicpu
157 )159 )
158endif ()160endif ()
@@ -164,6 +166,7 @@ set(cpu_engine_src_test_files
164 cpu_engine/aicpu_optimizer_st.cpp166 cpu_engine/aicpu_optimizer_st.cpp
165 cpu_engine/aicpu_kernel_builder_st.cpp167 cpu_engine/aicpu_kernel_builder_st.cpp
166 cpu_engine/aicpu_pass_st.cpp168 cpu_engine/aicpu_pass_st.cpp
169+ cpu_engine/folding_st.cpp
167)170)
168 171 
169set(host_engine_src_files172set(host_engine_src_files
@@ -196,6 +199,7 @@ add_executable(cpu_engine_stest
196 ${cpu_engine_src_files}199 ${cpu_engine_src_files}
197 ${cpu_engine_src_test_files}200 ${cpu_engine_src_test_files}
198 ${engine_common_stub_src_files}201 ${engine_common_stub_src_files}
202+ ${engine_common_stub_src_path}/stub/aicpu/aicpu_stub.cpp
199)203)
200 204 
201add_executable(host_engine_stest205add_executable(host_engine_stest
@@ -0,0 +1,73 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <gtest/gtest.h>
12+#include "aicpu_const_folding/folding.h"
13+#include "stub.h"
14+ 
15+TEST(AicpuConstFoldingST, InitCpuConstantFoldingNew_001) {
16+ int32_t ret = InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
17+ ASSERT_EQ(ret, 0);
18+}
19+ 
20+TEST(AicpuConstFoldingST, CpuConstantFoldingComputeNew_001) {
21+ ge::Operator op("testop");
22+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
23+ ge::GeTensorDesc testTensorDesc;
24+ ge::GeShape testgeshape;
25+ testgeshape.SetDimNum(2);
26+ testTensorDesc.SetShape(testgeshape);
27+ op_desc->AddInputDesc("testop", testTensorDesc);
28+ op_desc->AddOutputDesc("testop", testTensorDesc);
29+ ge::AscendString attr1 = "attr1";
30+ op.SetAttr("testattr1", attr1);
31+ float32_t attr2 = 0;
32+ op.SetAttr("testattr2", attr2);
33+ int32_t attr3 = 0;
34+ op.SetAttr("attr3", attr3);
35+ bool attr4 = true;
36+ op.SetAttr("attr4", attr4);
37+ ge::DataType attr5 = ge::DT_FLOAT;
38+ op.SetAttr("attr5", attr5);
39+ ge::Tensor attr6;
40+ op.SetAttr("attr6", attr6);
41+ 
42+ std::vector<ge::AscendString> attrList1;
43+ attrList1.push_back("attrList1");
44+ op.SetAttr("attrList1", attrList1);
45+ std::vector<float32_t> attrList2;
46+ attrList2.push_back(0);
47+ op.SetAttr("attrList2", attrList2);
48+ std::vector<int32_t> attrList3;
49+ attrList3.push_back(0);
50+ op.SetAttr("attrList3", attrList3);
51+ std::vector<bool> attrList4;
52+ attrList4.push_back(true);
53+ op.SetAttr("attrList4", attrList4);
54+ std::vector<ge::DataType> attrList5;
55+ attrList5.push_back(ge::DT_FLOAT);
56+ op.SetAttr("attrList5", attrList5);
57+ std::vector<ge::Tensor> attrList6;
58+ ge::Tensor testtensor;
59+ attrList6.push_back(testtensor);
60+ op.SetAttr("attrList6", attrList6);
61+ std::vector<std::vector<int64_t>> attrList7;
62+ std::vector<int64_t> testvec;
63+ testvec.push_back(0);
64+ attrList7.push_back(testvec);
65+ op.SetAttr("attrList7", attrList7);
66+ std::map<std::string, const ge::Tensor> inputs;
67+ std::map<std::string, ge::Tensor> outputs;
68+ ge::Tensor testTensor;
69+ inputs.emplace("testop", testTensor);
70+ outputs.emplace("testop", testTensor);
71+ int32_t ret = CpuConstantFoldingComputeNew(op, inputs, outputs);
72+ ASSERT_EQ(ret, 0);
73+}
@@ -18,6 +18,7 @@ set(engine_common_stub_files
18 ${CMAKE_CURRENT_SOURCE_DIR}/platform_info_stub.cpp18 ${CMAKE_CURRENT_SOURCE_DIR}/platform_info_stub.cpp
19 ${CMAKE_CURRENT_SOURCE_DIR}/stub.cpp19 ${CMAKE_CURRENT_SOURCE_DIR}/stub.cpp
20 ${CMAKE_CURRENT_SOURCE_DIR}/util/util_stub.cpp20 ${CMAKE_CURRENT_SOURCE_DIR}/util/util_stub.cpp
21+ ${CMAKE_CURRENT_SOURCE_DIR}/aicpu/aicpu_stub.cpp
21 ${PROTO_HDRS}22 ${PROTO_HDRS}
22)23)
23 24 
@@ -58,6 +59,7 @@ target_link_libraries(stub_for_aicpu PRIVATE
58 runtime_aicpu_stub59 runtime_aicpu_stub
59 ascend_protobuf60 ascend_protobuf
60 json61 json
62+ aicpu_headers
61 cce_headers63 cce_headers
62)64)
63 65 
@@ -0,0 +1,74 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "cpu_context.h"
12+#include "cpu_kernel_register.h"
13+#include "cpu_kernel.h"
14+ 
15+namespace aicpu {
16+CpuKernelContext::CpuKernelContext(DeviceType type) {
17+ (void)type;
18+}
19+ 
20+uint32_t CpuKernelContext::Init(void *nodeDef) {
21+ (void)nodeDef;
22+ return 0;
23+}
24+ 
25+CpuKernelRegister &CpuKernelRegister::Instance() {
26+ static CpuKernelRegister instance;
27+ return instance;
28+}
29+ 
30+class TestCpuKernel : public CpuKernel {
31+ public:
32+ TestCpuKernel() = default;
33+ ~TestCpuKernel() = default;
34+ uint32_t Compute(CpuKernelContext &ctx) override {
35+ return 0;
36+ };
37+};
38+ 
39+std::shared_ptr<CpuKernel> CpuKernelRegister::GetCpuKernel(const std::string &opType) {
40+ std::shared_ptr<CpuKernel> testCpuKernel = MakeShared<TestCpuKernel>();
41+ return testCpuKernel;
42+}
43+ 
44+std::shared_ptr<CpuKernel> CpuKernelRegister::GetCpuKernelV2(const std::string &opType) {
45+ std::shared_ptr<CpuKernel> testCpuKernel = MakeShared<TestCpuKernel>();
46+ return testCpuKernel;
47+}
48+ 
49+bool CpuKernelRegister::IsRegisteredV2(const std::string &opType) const {
50+ (void)opType;
51+ return true;
52+}
53+ 
54+uint32_t CpuKernelRegister::RunCpuKernel(CpuKernelContext &ctx) {
55+ return 0;
56+}
57+ 
58+uint32_t CpuKernelRegister::RunCpuKernelV2(CpuKernelContext &ctx) {
59+ return 0;
60+}
61+ 
62+std::vector<std::string> CpuKernelRegister::GetAllRegisteredOpTypes() const {
63+ std::vector<std::string> ret;
64+ ret.push_back("testop");
65+ return ret;
66+}
67+ 
68+std::vector<std::string> CpuKernelRegister::GetAllRegisteredOpTypesV2() const {
69+ std::vector<std::string> ret;
70+ ret.push_back("testopV2");
71+ return ret;
72+}
73+ 
74+} // namespace aicpu
@@ -129,6 +129,7 @@ set(cpu_engine_src_files
129 ${engine_src_path}/cpu_engine/aicpu_engine/kernel_builder/aicpu_kernel_builder.cpp129 ${engine_src_path}/cpu_engine/aicpu_engine/kernel_builder/aicpu_kernel_builder.cpp
130 ${engine_src_path}/cpu_engine/common/kernel_builder/cpu_kernel_builder.cpp130 ${engine_src_path}/cpu_engine/common/kernel_builder/cpu_kernel_builder.cpp
131 ${engine_src_path}/cpu_engine/common/optimizer/cpu_optimizer.cpp131 ${engine_src_path}/cpu_engine/common/optimizer/cpu_optimizer.cpp
132+ ${engine_src_path}/cpu_engine/aicpu_const_folding/folding.cc
132)133)
133 134 
134if (BUILD_OPEN_PROJECT OR ENABLE_OPEN_SRC)135if (BUILD_OPEN_PROJECT OR ENABLE_OPEN_SRC)
@@ -154,6 +155,7 @@ else ()
154 ${CMAKE_BINARY_DIR}/proto/aicpu155 ${CMAKE_BINARY_DIR}/proto/aicpu
155 ${CMAKE_BINARY_DIR}/proto/aicpu/proto156 ${CMAKE_BINARY_DIR}/proto/aicpu/proto
156 ${METADEF_DIR}/inc157 ${METADEF_DIR}/inc
158+ ${TOP_DIR}/inc/aicpu/cpu_kernels
157 ${TOP_DIR}/inc/external/aicpu159 ${TOP_DIR}/inc/external/aicpu
158 )160 )
159endif ()161endif ()
@@ -165,6 +167,7 @@ set(cpu_engine_src_test_files
165 cpu_engine/aicpu_optimizer_ut.cpp167 cpu_engine/aicpu_optimizer_ut.cpp
166 cpu_engine/aicpu_kernel_builder_ut.cpp168 cpu_engine/aicpu_kernel_builder_ut.cpp
167 cpu_engine/aicpu_pass_ut.cpp169 cpu_engine/aicpu_pass_ut.cpp
170+ cpu_engine/folding_ut.cpp
168)171)
169 172 
170set(host_engine_src_files173set(host_engine_src_files
@@ -198,6 +201,7 @@ add_executable(cpu_engine_utest
198 ${cpu_engine_src_files}201 ${cpu_engine_src_files}
199 ${cpu_engine_src_test_files}202 ${cpu_engine_src_test_files}
200 ${engine_common_stub_src_files}203 ${engine_common_stub_src_files}
204+ ${engine_common_stub_src_path}/stub/aicpu/aicpu_stub.cpp
201)205)
202 206 
203add_executable(host_engine_utest207add_executable(host_engine_utest
@@ -0,0 +1,265 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <gtest/gtest.h>
12+#include <cstdlib>
13+#include <sys/stat.h>
14+#include <sys/types.h>
15+#include <unistd.h>
16+#include <fstream>
17+#include <mutex>
18+#include "aicpu_const_folding/folding.h"
19+#include "stub.h"
20+ 
21+namespace {
22+std::mutex &GetEnvMutex() {
23+ static std::mutex env_mutex;
24+ return env_mutex;
25+}
26+ 
27+bool ReadEnvSafe(const char *name, std::string &value) {
28+ std::lock_guard<std::mutex> guard(GetEnvMutex());
29+ const char *raw = std::getenv(name);
30+ if (raw == nullptr) {
31+ return false;
32+ }
33+ value.assign(raw);
34+ return true;
35+}
36+ 
37+void SetEnvSafe(const char *name, const char *value, int overwrite) {
38+ std::lock_guard<std::mutex> guard(GetEnvMutex());
39+ (void)setenv(name, value, overwrite);
40+}
41+ 
42+void UnsetEnvSafe(const char *name) {
43+ std::lock_guard<std::mutex> guard(GetEnvMutex());
44+ (void)unsetenv(name);
45+}
46+ 
47+void SetAllTestAttrs(ge::Operator &op) {
48+ ge::AscendString attr1 = "attr1";
49+ op.SetAttr("testattr1", attr1);
50+ float32_t attr2 = 0;
51+ op.SetAttr("testattr2", attr2);
52+ int32_t attr3 = 0;
53+ op.SetAttr("attr3", attr3);
54+ bool attr4 = true;
55+ op.SetAttr("attr4", attr4);
56+ ge::DataType attr5 = ge::DT_FLOAT;
57+ op.SetAttr("attr5", attr5);
58+ ge::Tensor attr6;
59+ op.SetAttr("attr6", attr6);
60+ 
61+ std::vector<ge::AscendString> attrList1;
62+ attrList1.push_back("attrList1");
63+ op.SetAttr("attrList1", attrList1);
64+ std::vector<float32_t> attrList2;
65+ attrList2.push_back(0);
66+ op.SetAttr("attrList2", attrList2);
67+ std::vector<int32_t> attrList3;
68+ attrList3.push_back(0);
69+ op.SetAttr("attrList3", attrList3);
70+ std::vector<bool> attrList4;
71+ attrList4.push_back(true);
72+ op.SetAttr("attrList4", attrList4);
73+ std::vector<ge::DataType> attrList5;
74+ attrList5.push_back(ge::DT_FLOAT);
75+ op.SetAttr("attrList5", attrList5);
76+ std::vector<ge::Tensor> attrList6;
77+ ge::Tensor testtensor;
78+ attrList6.push_back(testtensor);
79+ op.SetAttr("attrList6", attrList6);
80+ std::vector<std::vector<int64_t>> attrList7;
81+ std::vector<int64_t> testvec;
82+ testvec.push_back(0);
83+ attrList7.push_back(testvec);
84+ op.SetAttr("attrList7", attrList7);
85+}
86+} // namespace
87+ 
88+class AicpuConstFoldingTest : public ::testing::Test {
89+ protected:
90+ void SetUp() override {
91+ has_saved_home_path_ = ReadEnvSafe("ASCEND_HOME_PATH", saved_home_path_);
92+ }
93+ void TearDown() override {
94+ if (has_saved_home_path_) {
95+ SetEnvSafe("ASCEND_HOME_PATH", saved_home_path_.c_str(), 1);
96+ } else {
97+ UnsetEnvSafe("ASCEND_HOME_PATH");
98+ }
99+ }
100+ std::string saved_home_path_;
101+ bool has_saved_home_path_ = false;
102+};
103+ 
104+TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_Success) {
105+ setenv("ASCEND_HOME_PATH", "/tmp", 1);
106+ int32_t ret = InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
107+ ASSERT_EQ(ret, 0);
108+}
109+ 
110+TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_NoEnvFail) {
111+ unsetenv("ASCEND_HOME_PATH");
112+ int32_t ret = InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
113+ ASSERT_EQ(ret, -1);
114+}
115+ 
116+TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_LoadSoTraversal) {
117+ std::string tmp_dir = "/tmp/test_folding_ut_" + std::to_string(getpid());
118+ std::string host_cpu_dir = tmp_dir + "/opp/built-in/op_impl/host_cpu/";
119+ std::string cmd_mkdir = "mkdir -p " + host_cpu_dir;
120+ ASSERT_EQ(system(cmd_mkdir.c_str()), 0);
121+ 
122+ // Create files matching libopconstant_folding_*.so pattern
123+ std::ofstream(host_cpu_dir + "libopconstant_folding_math.so").close();
124+ std::ofstream(host_cpu_dir + "libopconstant_folding_nn.so").close();
125+ std::ofstream(host_cpu_dir + "libopconstant_folding_cv.so").close();
126+ // Create files that should NOT match the pattern
127+ std::ofstream(host_cpu_dir + "libother.so").close();
128+ std::ofstream(host_cpu_dir + "libmath_constant_folding_ops.so").close();
129+ std::ofstream(host_cpu_dir + "notlib_constant_folding_ops.so").close();
130+ // libconstant_folding_ops.so should be excluded (loaded by host_cpu_engine separately)
131+ std::ofstream(host_cpu_dir + "libconstant_folding_ops.so").close();
132+ 
133+ setenv("ASCEND_HOME_PATH", tmp_dir.c_str(), 1);
134+ int32_t ret = InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
135+ // Init succeeds even if dlopen fails on empty .so files (just warns)
136+ ASSERT_EQ(ret, 0);
137+ 
138+ std::string cmd_rm = "rm -rf " + tmp_dir;
139+ system(cmd_rm.c_str());
140+}
141+ 
142+TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_PathWithTrailingSlash) {
143+ setenv("ASCEND_HOME_PATH", "/tmp/", 1);
144+ int32_t ret = InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
145+ ASSERT_EQ(ret, 0);
146+}
147+ 
148+TEST_F(AicpuConstFoldingTest, CpuConstantFoldingComputeNew_Success) {
149+ setenv("ASCEND_HOME_PATH", "/tmp", 1);
150+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
151+ 
152+ ge::Operator op("testop");
153+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
154+ ge::GeTensorDesc testTensorDesc;
155+ ge::GeShape testgeshape;
156+ testgeshape.SetDimNum(2);
157+ testTensorDesc.SetShape(testgeshape);
158+ op_desc->AddInputDesc("testop", testTensorDesc);
159+ op_desc->AddOutputDesc("testop", testTensorDesc);
160+ 
161+ SetAllTestAttrs(op);
162+ 
163+ std::map<std::string, const ge::Tensor> inputs;
164+ std::map<std::string, ge::Tensor> outputs;
165+ ge::Tensor testTensor;
166+ inputs.emplace("testop", testTensor);
167+ outputs.emplace("testop", testTensor);
168+ int32_t ret = CpuConstantFoldingComputeNew(op, inputs, outputs);
169+ ASSERT_EQ(ret, 0);
170+}
171+ 
172+TEST_F(AicpuConstFoldingTest, CpuConstantFoldingComputeNew_MissingInput) {
173+ setenv("ASCEND_HOME_PATH", "/tmp", 1);
174+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
175+ 
176+ ge::Operator op("testop");
177+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
178+ ge::GeTensorDesc testTensorDesc;
179+ op_desc->AddInputDesc("input1", testTensorDesc);
180+ op_desc->AddOutputDesc("output1", testTensorDesc);
181+ // Deliberately not providing required input
182+ std::map<std::string, const ge::Tensor> inputs;
183+ std::map<std::string, ge::Tensor> outputs;
184+ ge::Tensor testTensor;
185+ outputs.emplace("output1", testTensor);
186+ int32_t ret = CpuConstantFoldingComputeNew(op, inputs, outputs);
187+ ASSERT_EQ(ret, -1);
188+}
189+ 
190+TEST_F(AicpuConstFoldingTest, CpuConstantFoldingComputeNew_MissingOutput) {
191+ setenv("ASCEND_HOME_PATH", "/tmp", 1);
192+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
193+ 
194+ ge::Operator op("testop");
195+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
196+ ge::GeTensorDesc testTensorDesc;
197+ op_desc->AddInputDesc("input1", testTensorDesc);
198+ op_desc->AddOutputDesc("output1", testTensorDesc);
199+ std::map<std::string, const ge::Tensor> inputs;
200+ std::map<std::string, ge::Tensor> outputs;
201+ ge::Tensor testTensor;
202+ inputs.emplace("input1", testTensor);
203+ // Deliberately not providing required output
204+ int32_t ret = CpuConstantFoldingComputeNew(op, inputs, outputs);
205+ ASSERT_EQ(ret, -1);
206+}
207+ 
208+// 验证: 多个 libopconstant_folding_*.so 共存场景下, Init 不会因为
209+// 每个 so 都有独立的 CpuKernelRegister 单例而发生 this/成员函数错配的
210+// coredump, Compute 回落到 V1 路径仍能正常工作.
211+TEST_F(AicpuConstFoldingTest, InitCpuConstantFoldingNew_MultiOpsSoNoCrash) {
212+ std::string tmp_dir = "/tmp/test_folding_ut_multi_" + std::to_string(getpid());
213+ std::string host_cpu_dir = tmp_dir + "/opp/built-in/op_impl/host_cpu/";
214+ std::string cmd_mkdir = "mkdir -p " + host_cpu_dir;
215+ ASSERT_EQ(system(cmd_mkdir.c_str()), 0);
216+ 
217+ std::ofstream(host_cpu_dir + "libopconstant_folding_math.so").close();
218+ std::ofstream(host_cpu_dir + "libopconstant_folding_nn.so").close();
219+ std::ofstream(host_cpu_dir + "libopconstant_folding_cv.so").close();
220+ 
221+ setenv("ASCEND_HOME_PATH", tmp_dir.c_str(), 1);
222+ int32_t init_ret =
223+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
224+ ASSERT_EQ(init_ret, 0);
225+ 
226+ ge::Operator op("testop");
227+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
228+ ge::GeTensorDesc tensor_desc;
229+ op_desc->AddInputDesc("testop", tensor_desc);
230+ op_desc->AddOutputDesc("testop", tensor_desc);
231+ std::map<std::string, const ge::Tensor> inputs;
232+ std::map<std::string, ge::Tensor> outputs;
233+ ge::Tensor t;
234+ inputs.emplace("testop", t);
235+ outputs.emplace("testop", t);
236+ int32_t rc = CpuConstantFoldingComputeNew(op, inputs, outputs);
237+ ASSERT_EQ(rc, 0);
238+ 
239+ std::string cmd_rm = "rm -rf " + tmp_dir;
240+ (void)system(cmd_rm.c_str());
241+}
242+ 
243+// 验证: 当 V2 不命中时, Compute 会回退到本地 V1 GetCpuKernel 路径.
244+// 覆盖 opbase 侧 "GetCpuKernelV2 不再内建回退" 后 ge 侧的外部兜底链路.
245+TEST_F(AicpuConstFoldingTest, CpuConstantFoldingComputeNew_V2Miss_FallbackV1) {
246+ setenv("ASCEND_HOME_PATH", "/tmp", 1);
247+ int32_t init_ret =
248+ InitCpuConstantFoldingNew([]() -> ge::HostCpuOp * { return new (std::nothrow) ge::HostCpuTestOp(); });
249+ ASSERT_EQ(init_ret, 0);
250+ 
251+ // stub 里 V1 的 GetCpuKernel 总返回非空, V2 反向索引里不会有 "unknown_op",
252+ // Compute 应当走 V1 路径返回 0.
253+ ge::Operator op("unknown_op");
254+ auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
255+ ge::GeTensorDesc tensor_desc;
256+ op_desc->AddInputDesc("unknown_op", tensor_desc);
257+ op_desc->AddOutputDesc("unknown_op", tensor_desc);
258+ std::map<std::string, const ge::Tensor> inputs;
259+ std::map<std::string, ge::Tensor> outputs;
260+ ge::Tensor t;
261+ inputs.emplace("unknown_op", t);
262+ outputs.emplace("unknown_op", t);
263+ int32_t rc = CpuConstantFoldingComputeNew(op, inputs, outputs);
264+ ASSERT_EQ(rc, 0);
265+}