已合并
fix: 修正动态shape静态子图HCCL零拷贝判断逻辑 #4321
tangqunzhang创建于 8月10日
fix: 修正动态shape静态子图HCCL零拷贝判断逻辑 #4321
已合并
tangqunzhang创建于 8月10日
共 5 个文件变更+225-57
@@ -1283,13 +1283,19 @@ void BlockMemAssigner::UpdateOpTensorMemType(const std::list<NodeIndexIO> &node_
1283 }1283 }
1284 }1284 }
1285}1285}
1286+ 
1286bool BlockMemAssigner::IsZeroCopyBlock(const NodePtr &node, uint32_t output_index, bool continuous,1287bool BlockMemAssigner::IsZeroCopyBlock(const NodePtr &node, uint32_t output_index, bool continuous,
1287 size_t output_size) const {1288 size_t output_size) const {
1288 std::string op_type(node->GetTypePtr());1289 std::string op_type(node->GetTypePtr());
1290+ 
1291+ // 现状:
1292+ // 动态shape静态子图的输入,按零拷贝处理(ge执行流程不支持输入做拷贝处理,搞成非零拷贝会有精度问题,输入数据错误)
1293+ // 动态shape静态子图的输出,按非零拷贝处理(搞成零拷贝需要hccl算子支持地址刷新,会导致性能劣化)
1289 if (NodeUtils::IsDynamicShape(node)) {1294 if (NodeUtils::IsDynamicShape(node)) {
1290 if (compute_graph_.get() != node->GetOwnerComputeGraphBarePtr()) {1295 if (compute_graph_.get() != node->GetOwnerComputeGraphBarePtr()) {
1291 return false;1296 return false;
1292 }1297 }
1298+ 
1293 if (OpTypeUtils::IsDataNode(op_type)) {1299 if (OpTypeUtils::IsDataNode(op_type)) {
1294 return (!continuous);1300 return (!continuous);
1295 }1301 }
@@ -1331,14 +1337,14 @@ bool BlockMemAssigner::IsZeroCopyBlock(const NodePtr &node, uint32_t output_inde
1331 return false;1337 return false;
1332 }1338 }
1333 // Data flow to unsupported zero copy task type eg. memcpy, can never zero copied1339 // Data flow to unsupported zero copy task type eg. memcpy, can never zero copied
1334- return IsNodeAndPeerNodeTaskSupportZeroCopy(node, output_index, is_feature_map_refreshable_);1340+ return IsNodeAndPeerNodeTaskSupportZeroCopy(node, output_index);
1335 }1341 }
1336 1342 
1337 // Only node output that flow to sure one output maybe zero copied1343 // Only node output that flow to sure one output maybe zero copied
1338 if (GetOutputFlowToNetoutputNum(node, output_index, compute_graph_, symbol_to_anchors_, anchor_to_symbol_) ==1344 if (GetOutputFlowToNetoutputNum(node, output_index, compute_graph_, symbol_to_anchors_, anchor_to_symbol_) ==
1339 1U) { // 1U means output to only one netoutput1345 1U) { // 1U means output to only one netoutput
1340 // Output from unsupported task type eg. memcpy, can never zero copied1346 // Output from unsupported task type eg. memcpy, can never zero copied
1341- return IsNodeAndPeerNodeTaskSupportZeroCopy(node, output_index, is_feature_map_refreshable_);1347+ return IsNodeAndPeerNodeTaskSupportZeroCopy(node, output_index);
1342 }1348 }
1343 1349 
1344 return false;1350 return false;
@@ -1698,7 +1704,7 @@ Status BlockMemAssigner::ApplyContinuousMemWithMng(const NodePtr &n, int32_t idx
1698 if (iter != symbol_mem_reuse_info_.cend()) {1704 if (iter != symbol_mem_reuse_info_.cend()) {
1699 block->is_fixed_addr_prior_ = (block->is_fixed_addr_prior_ || iter->second.is_fixed_addr_prior_);1705 block->is_fixed_addr_prior_ = (block->is_fixed_addr_prior_ || iter->second.is_fixed_addr_prior_);
1700 }1706 }
1701- MarkReuseZeroCopyBlockFlag(n, block, idx, is_feature_map_refreshable_);1707+ MarkReuseZeroCopyBlockFlag(n, block, idx);
1702 MarkZeroCopyBlockAttr(bool_attr_, op_desc, block->is_zero_copy_, OpMemoryType::kOutput, idx);1708 MarkZeroCopyBlockAttr(bool_attr_, op_desc, block->is_zero_copy_, OpMemoryType::kOutput, idx);
1703 GELOGI(1709 GELOGI(
1704 "[ContinuousMem]Node name: %s index:%u size:%zu ref count: %d, zero copy:%d, fixed addr prior: %d, "1710 "[ContinuousMem]Node name: %s index:%u size:%zu ref count: %d, zero copy:%d, fixed addr prior: %d, "
@@ -2030,7 +2036,7 @@ MemoryBlock *BlockMemAssigner::ApplyOutMemory(const NodePtr &n, uint32_t index,
2030 block_size, block->ref_count_, out_count, block->is_zero_copy_, block->is_fixed_addr_prior_);2036 block_size, block->ref_count_, out_count, block->is_zero_copy_, block->is_fixed_addr_prior_);
2031 }2037 }
2032 2038 
2033- MarkReuseZeroCopyBlockFlag(n, block, index, is_feature_map_refreshable_);2039+ MarkReuseZeroCopyBlockFlag(n, block, index);
2034 MarkZeroCopyBlockAttr(bool_attr_, node_op_desc, block->is_zero_copy_, OpMemoryType::kOutput, index);2040 MarkZeroCopyBlockAttr(bool_attr_, node_op_desc, block->is_zero_copy_, OpMemoryType::kOutput, index);
2035 GELOGI("Node name: %s index:%u size:%zu ref count: %d, out count: %d zero copy:%d, out node need continuous input %d",2041 GELOGI("Node name: %s index:%u size:%zu ref count: %d, out count: %d zero copy:%d, out node need continuous input %d",
2036 n->GetNamePtr(), index, block_size, block->ref_count_, out_count, block->is_zero_copy_,2042 n->GetNamePtr(), index, block_size, block->ref_count_, out_count, block->is_zero_copy_,
@@ -33,17 +33,20 @@ namespace {
33const std::string kOffline = "offline";33const std::string kOffline = "offline";
34}34}
35 35 
36+// 地址不可刷新时不能做零拷贝,也不能和零拷贝节点内存进行复用
37+// 和Data、Netoutput连接时用于判断是否可零拷贝,和其他节点连接是用于判断是否可以和零拷贝节点进行复用
36bool IsNodeSupportZeroCopy(const ge::NodePtr &node) {38bool IsNodeSupportZeroCopy(const ge::NodePtr &node) {
37 bool is_support_zero_copy = ge::MemLayoutConflictUtil::IsAddressRefreshable(node);39 bool is_support_zero_copy = ge::MemLayoutConflictUtil::IsAddressRefreshable(node);
38 if (!is_support_zero_copy) {40 if (!is_support_zero_copy) {
39 GELOGI("Op[%s] not support zero copy", node->GetName().c_str());41 GELOGI("Op[%s] not support zero copy", node->GetName().c_str());
40 } else {42 } else {
41- // 1.IsAddressRefreshable在动态shape静态子图场景认为hccl算子是可刷新的,实际上因为处理阶段有差异,43+ // IsAddressRefreshable在动态shape静态子图场景认为hccl算子是可刷新的,实际上因为处理阶段有差异,
42- // 比如hccl判断时还未拆图,可能导致结果不一致44+ // 比如hccl判断时还未拆图,可能导致结果不一致,这里还是统一使用IsHcomNodeNotSupportAddrRefresh的结果
43- // 2.静态shape根图图场景,把hccl搞成可刷新会导致性能劣化45+ // 另外静态子图里hccl支持刷新会有性能劣化,hccl内部会做数据拷贝等额外处理
44- // 因此IsGraphFeatureMapRefreshable为true时,这里还是统一使用IsHcomNodeNotSupportAddrRefresh的结果,和原有处理保持一致46+ const auto root_graph = GraphUtils::FindRootGraph(node->GetOwnerComputeGraph());
45- if (ge::MemLayoutConflictUtil::IsGraphFeatureMapRefreshable(node->GetOwnerComputeGraph()) &&47+ const bool is_dynamic_shape_sub_graph = (root_graph != nullptr) && root_graph->GetGraphUnknownFlag() &&
46- ge::OpUtils::IsHcomNodeNotSupportAddrRefresh(node->GetOpDesc())) {48+ (!node->GetOwnerComputeGraph()->GetGraphUnknownFlag());
49+ if (is_dynamic_shape_sub_graph && ge::OpUtils::IsHcomNodeNotSupportAddrRefresh(node->GetOpDesc())) {
47 GELOGI("hccl engine op[%s] not support zero copy", node->GetName().c_str());50 GELOGI("hccl engine op[%s] not support zero copy", node->GetName().c_str());
48 is_support_zero_copy = false;51 is_support_zero_copy = false;
49 }52 }
@@ -211,8 +214,7 @@ void SetReleaseBlockLifeEnd(MemoryBlock *to_release, int64_t stream_id) {
211 to_release->SetLifeTimeEnd(max_end_life_time, to_release->stream_id_);214 to_release->SetLifeTimeEnd(max_end_life_time, to_release->stream_id_);
212}215}
213 216 
214-void MarkReuseZeroCopyBlockFlag(const NodePtr &n, MemoryBlock *const block, const uint32_t index,217+void MarkReuseZeroCopyBlockFlag(const NodePtr &n, MemoryBlock *const block, const uint32_t index) {
215- bool is_feature_map_refreshable) {
216 auto node_op_desc = n->GetOpDescBarePtr();218 auto node_op_desc = n->GetOpDescBarePtr();
217 219 
218 // 输出连续内存不能做零拷贝,同时NoPadding且Reuse的也不能做零拷贝220 // 输出连续内存不能做零拷贝,同时NoPadding且Reuse的也不能做零拷贝
@@ -235,35 +237,12 @@ void MarkReuseZeroCopyBlockFlag(const NodePtr &n, MemoryBlock *const block, cons
235 block->is_reuse_zero_copy_ = false;237 block->is_reuse_zero_copy_ = false;
236 }238 }
237 239 
238- // data直连特殊的rts算子且不可刷新状态下,不能做零拷贝240+ GELOGD("Node name: %s index: %d, can_reuse_zero_copy: %s.", n->GetNamePtr(), index,
239- const static std::set<std::string> kTaskUnsupportZeroCopyOp{ge::STREAMSWITCH, ge::LABELSWITCHBYINDEX};241+ can_reuse_zero_copy ? "true" : "false");
240- auto out_anchor = n->GetOutDataAnchor(static_cast<int32_t>(index));
241- bool data_connect_unsupport_zero_copy = false;
242- if (OpTypeUtils::IsDataNode(node_op_desc->GetType()) && (!is_feature_map_refreshable) && (out_anchor != nullptr)) {
243- auto peer_anchors = out_anchor->GetPeerInDataAnchorsPtr();
244- data_connect_unsupport_zero_copy =
245- std::any_of(peer_anchors.begin(), peer_anchors.end(), [](const ge::InDataAnchor *anchor) {
246- return ((anchor != nullptr) && (anchor->GetOwnerNodeBarePtr() != nullptr) &&
247- (kTaskUnsupportZeroCopyOp.count(anchor->GetOwnerNodeBarePtr()->GetTypePtr()) > 0U));
248- });
249- }
250- 
251- if (data_connect_unsupport_zero_copy) {
252- block->is_reuse_zero_copy_ = false;
253- block->is_zero_copy_ = false;
254- }
255- 
256- GELOGD("Node name: %s index: %d, can_reuse_zero_copy: %s, data_connect_unsupport_zero_copy: %s ", n->GetNamePtr(),
257- index, can_reuse_zero_copy ? "true" : "false", data_connect_unsupport_zero_copy ? "true" : "false");
258}242}
259 243 
260-bool IsNodeAndPeerNodeTaskSupportZeroCopy(const ge::NodePtr &node, uint32_t output_index,244+bool IsNodeAndPeerNodeTaskSupportZeroCopy(const ge::NodePtr &node, uint32_t output_index) {
261- bool is_feature_map_refreshable) {
262 GELOGD("Check node %s and peer node of output %u task zero copy supported", node->GetNamePtr(), output_index);245 GELOGD("Check node %s and peer node of output %u task zero copy supported", node->GetNamePtr(), output_index);
263- if (is_feature_map_refreshable) {
264- return true;
265- }
266- 
267 if (!IsNodeSupportZeroCopy(node)) {246 if (!IsNodeSupportZeroCopy(node)) {
268 return false;247 return false;
269 }248 }
@@ -30,10 +30,8 @@ bool IsKnownSubgraphData(const ge::Node *node);
30void SetReleaseBlockLifeEnd(ge::MemoryBlock *to_release, int64_t stream_id);30void SetReleaseBlockLifeEnd(ge::MemoryBlock *to_release, int64_t stream_id);
31void MarkZeroCopyBlockAttr(std::vector<TAttr<bool>> &bool_attr, const ge::OpDesc *const op_desc, bool is_zero_copy,31void MarkZeroCopyBlockAttr(std::vector<TAttr<bool>> &bool_attr, const ge::OpDesc *const op_desc, bool is_zero_copy,
32 OpMemoryType mem_type, uint32_t out_index);32 OpMemoryType mem_type, uint32_t out_index);
33-void MarkReuseZeroCopyBlockFlag(const NodePtr &n, MemoryBlock *const block, const uint32_t index,33+void MarkReuseZeroCopyBlockFlag(const NodePtr &n, MemoryBlock *const block, const uint32_t index);
34- bool is_feature_map_refreshable);34+bool IsNodeAndPeerNodeTaskSupportZeroCopy(const ge::NodePtr &node, uint32_t output_index);
35-bool IsNodeAndPeerNodeTaskSupportZeroCopy(const ge::NodePtr &node, uint32_t output_index,
36- bool is_feature_map_refreshable);
37 35 
38} // namespace ge36} // namespace ge
39 37 
@@ -177,7 +177,6 @@ class FakeOpsKernelInfoStore : public OpsKernelInfoStore {
177 }177 }
178};178};
179FakeOpsKernelInfoStore g_fake_ops_kernel_info_store;179FakeOpsKernelInfoStore g_fake_ops_kernel_info_store;
180- 
181Status GenerateTaskForHcomAllReduce(const Node &node, RunContext &run_context, std::vector<domi::TaskDef> &tasks) {180Status GenerateTaskForHcomAllReduce(const Node &node, RunContext &run_context, std::vector<domi::TaskDef> &tasks) {
182 std::cout << "======node.GetType():" << node.GetType() << std::endl;181 std::cout << "======node.GetType():" << node.GetType() << std::endl;
183 if (node.GetType() != "HcomAllReduce") {182 if (node.GetType() != "HcomAllReduce") {
@@ -8790,4 +8789,186 @@ TEST_F(FmMemoryRefreshTest, annotated_args_in_dynamic_root_known_subgraph_refres
8790 runtime_stub.Clear();8789 runtime_stub.Clear();
8791}8790}
8792 8791 
8792+/*
8793+ * 动态shape图有两个静态子图,静态子图里有hccl算子
8794+ * 子图1: data -> hcom_1 -> netoutput (hcom输出作为子图输出)
8795+ * 子图2: data(子图输入) -> hcom_2 (hcom输入是子图输入)
8796+ * root: data_1 -> known_op1 -> root_netoutput
8797+ * data_2 -> known_op2 -> root_netoutput
8798+ */
8799+namespace {
8800+void VerifyZeroCopyInSubgraphs(const ComputeGraphPtr &root_graph) {
8801+ for (const auto &sub_graph : root_graph->GetAllSubgraphs()) {
8802+ if (sub_graph->GetGraphUnknownFlag()) {
8803+ continue;
8804+ }
8805+ for (const auto &node : sub_graph->GetAllNodes()) {
8806+ const auto &op_desc = node->GetOpDesc();
8807+ if (op_desc == nullptr) {
8808+ continue;
8809+ }
8810+ bool is_zero_copy = false;
8811+ (void)AttrUtils::GetBool(op_desc->GetOutputDescPtr(0), ATTR_IS_ZERO_COPY_BLOCK, is_zero_copy);
8812+ if (OpTypeUtils::IsDataNode(op_desc->GetType())) {
8813+ EXPECT_TRUE(is_zero_copy) << "data node " << op_desc->GetName() << " should be zero copy";
8814+ } else if (op_desc->GetType() == HCOMALLREDUCE) {
8815+ EXPECT_FALSE(is_zero_copy) << "hccl node " << op_desc->GetName() << " should not be zero copy";
8816+ }
8817+ }
8818+ }
8819+}
8820+ 
8821+std::vector<ge::Tensor> MakeTensor(const std::vector<int64_t> &data) {
8822+ TensorDesc desc(Shape({2, 2}));
8823+ desc.SetPlacement(Placement::kPlacementDevice);
8824+ ge::Tensor tensor{desc};
8825+ tensor.SetData(reinterpret_cast<uint8_t *>(const_cast<int64_t *>(data.data())), data.size() * sizeof(int64_t));
8826+ return {tensor};
8827+}
8828+ 
8829+OpDescPtr BuildHcclNode(const std::string &hcom_name, int64_t hcom_input_offset, int64_t data_output_offset) {
8830+ std::vector<int64_t> shape{2, 2};
8831+ std::vector<int64_t> memtype_list = {RT_MEMORY_HBM};
8832+ auto hcom = OP_CFG(HCOMALLREDUCE)
8833+ .TensorDesc(FORMAT_NCHW, DT_FLOAT, shape)
8834+ .InCnt(1)
8835+ .OutCnt(1)
8836+ .Attr(ATTR_NAME_MODIFY_INPUT, true)
8837+ .Attr(ATTR_NAME_INPUT_MEM_TYPE_LIST, memtype_list)
8838+ .Attr(ATTR_NAME_OUTPUT_MEM_TYPE_LIST, memtype_list)
8839+ .Build(hcom_name);
8840+ hcom->SetOpKernelLibName("ops_kernel_info_hccl");
8841+ hcom->SetWorkspace({0});
8842+ hcom->SetWorkspaceBytes({512});
8843+ hcom->SetInputOffset({hcom_input_offset});
8844+ hcom->SetOutputOffset({data_output_offset});
8845+ ge::AttrUtils::SetBool(hcom, ATTR_NAME_IS_FIXED_ADDR_PRIOR, true);
8846+ return hcom;
8847+}
8848+ 
8849+OpDescPtr BuildSubgraphDataNode(const std::string &name, int64_t output_offset) {
8850+ std::vector<int64_t> shape{2, 2};
8851+ auto data = OP_CFG("Data")
8852+ .TensorDesc(FORMAT_NCHW, DT_FLOAT, shape)
8853+ .InCnt(1)
8854+ .OutCnt(1)
8855+ .Attr(ATTR_NAME_PARENT_NODE_INDEX, 0)
8856+ .Attr(ATTR_NAME_INDEX, 0)
8857+ .Build(name);
8858+ data->SetOutputOffset({output_offset});
8859+ return data;
8860+}
8861+ 
8862+OpDescPtr BuildSubgraphNetOutputNode(const std::string &name, int64_t input_offset) {
8863+ std::vector<int64_t> shape{2, 2};
8864+ auto netoutput = OP_CFG(ge::NETOUTPUT)
8865+ .TensorDesc(FORMAT_NCHW, DT_FLOAT, shape)
8866+ .InCnt(1)
8867+ .OutCnt(1)
8868+ .InputAttr(0, ATTR_NAME_PARENT_NODE_INDEX, 0)
8869+ .Attr(TVM_ATTR_NAME_MAGIC, "RT_DEV_BINARY_MAGIC_ELF")
8870+ .Build(name);
8871+ netoutput->SetInputOffset({input_offset});
8872+ return netoutput;
8873+}
8874+ 
8875+ComputeGraphPtr SetupSubgraph(const Graph &sub_graph, const std::string &netoutput_name, const std::string &hcom_name) {
8876+ auto compute_graph = ge::GraphUtilsEx::GetComputeGraph(sub_graph);
8877+ compute_graph->SetGraphUnknownFlag(false);
8878+ compute_graph->FindNode(netoutput_name)->GetOpDesc()->SetSrcName({hcom_name});
8879+ compute_graph->FindNode(netoutput_name)->GetOpDesc()->SetSrcIndex({0});
8880+ return compute_graph;
8881+}
8882+void RunAndVerify(Session &session, uint32_t graph_id, const ComputeGraphPtr &root_graph,
8883+ GertRuntimeStub &runtime_stub) {
8884+ std::vector<int64_t> input_data(2 * 2, 0);
8885+ for (size_t i = 0; i < input_data.size(); ++i) {
8886+ input_data[i] = static_cast<int64_t>(i + 1) * 0x1000;
8887+ }
8888+ auto inputs = MakeTensor(input_data);
8889+ auto outputs = MakeTensor(std::vector<int64_t>(2 * 2, 0));
8890+ const auto summary = session.GetCompiledGraphSummary(graph_id);
8891+ EXPECT_NE(summary, nullptr);
8892+ size_t fix_feature_size = 0;
8893+ EXPECT_EQ(SUCCESS, summary->GetFixedFeatureMemorySize(fix_feature_size));
8894+ std::vector<uint8_t> fixed_feature_mem(fix_feature_size, 0);
8895+ EXPECT_EQ(SUCCESS, session.SetGraphFixedFeatureMemoryBase(graph_id, fixed_feature_mem.data(), fix_feature_size));
8896+ VerifyZeroCopyInSubgraphs(root_graph);
8897+ runtime_stub.Clear();
8898+ EXPECT_EQ(SUCCESS, session.RunGraphWithStreamAsync(graph_id, nullptr, inputs, outputs));
8899+ OpsKernelBuilderRegistry::GetInstance().Unregister("ops_kernel_info_hccl");
8900+ runtime_stub.Clear();
8901+}
8902+OpDescPtr BuildRootDataNode(const std::vector<int64_t> &shape) {
8903+ return OP_CFG("Data")
8904+ .TensorDesc(FORMAT_NCHW, DT_FLOAT, shape)
8905+ .InCnt(1)
8906+ .OutCnt(1)
8907+ .Attr(ATTR_NAME_INDEX, 0)
8908+ .Build("data_1");
8909+}
8910+ 
8911+OpDescPtr BuildPartitionedCallNode(const std::string &name, const std::vector<int64_t> &shape) {
8912+ return OP_CFG(ge::PARTITIONEDCALL).TensorDesc(FORMAT_NCHW, DT_FLOAT, shape).InCnt(1).OutCnt(1).Build(name);
8913+}
8914+ 
8915+OpDescPtr BuildRootNetOutputNode(const std::vector<int64_t> &shape) {
8916+ auto netoutput =
8917+ OP_CFG(ge::NETOUTPUT).TensorDesc(FORMAT_NCHW, DT_FLOAT, shape).InCnt(1).OutCnt(1).Build("root_netoutput");
8918+ netoutput->SetSrcName({"known_op2"});
8919+ netoutput->SetSrcIndex({0});
8920+ return netoutput;
8921+}
8922+} // namespace
8923+ 
8924+TEST_F(FmMemoryRefreshTest, hccl_zero_copy_dynamic_shape_two_static_subgraph) {
8925+ GertRuntimeStub runtime_stub;
8926+ MockForGenerateTask("ops_kernel_info_hccl", GenerateTaskForHcomAllReduce);
8927+ std::vector<int64_t> shape{2, 2};
8928+ 
8929+ auto data_sub1 = BuildSubgraphDataNode("data_sub1", 32);
8930+ auto hcom_1 = BuildHcclNode("hcom_1", 0, 32);
8931+ auto sub_1_netoutput = BuildSubgraphNetOutputNode("sub_1_netoutput", 0);
8932+ auto data_sub2 = BuildSubgraphDataNode("data_sub2", 64);
8933+ auto hcom_2 = BuildHcclNode("hcom_2", 16, 64);
8934+ auto sub_2_netoutput = BuildSubgraphNetOutputNode("sub_2_netoutput", 16);
8935+ auto known_op1 = BuildPartitionedCallNode("known_op1", shape);
8936+ auto known_op2 = BuildPartitionedCallNode("known_op2", shape);
8937+ auto data_1 = BuildRootDataNode(shape);
8938+ auto root_netoutput = BuildRootNetOutputNode(shape);
8939+ 
8940+ DEF_GRAPH(sub_1) {
8941+ CHAIN(NODE(data_sub1)->NODE(hcom_1)->NODE(sub_1_netoutput));
8942+ };
8943+ DEF_GRAPH(sub_2) {
8944+ CHAIN(NODE(data_sub2)->NODE(hcom_2)->NODE(sub_2_netoutput));
8945+ };
8946+ DEF_GRAPH(root) {
8947+ CHAIN(NODE(data_1)->EDGE(0, 0)->NODE(known_op1)->EDGE(0, 0)->NODE(known_op2)->EDGE(0, 0)->NODE(root_netoutput));
8948+ };
8949+ 
8950+ auto graph = ToGeGraph(root);
8951+ auto root_graph = ge::GraphUtilsEx::GetComputeGraph(graph);
8952+ root_graph->SetGraphUnknownFlag(true);
8953+ (void)AttrUtils::SetBool(root_graph, ATTR_NAME_DYNAMIC_SHAPE_PARTITIONED, true);
8954+ auto sub_graph1 = ToGeGraph(sub_1);
8955+ auto compute_graph1 = SetupSubgraph(sub_graph1, "sub_1_netoutput", "hcom_1");
8956+ auto sub_graph2 = ToGeGraph(sub_2);
8957+ auto compute_graph2 = SetupSubgraph(sub_graph2, "sub_2_netoutput", "hcom_2");
8958+ 
8959+ auto known_node1 = root_graph->FindNode("known_op1");
8960+ auto known_node2 = root_graph->FindNode("known_op2");
8961+ (void)AttrUtils::SetBool(known_node1->GetOpDesc(), ATTR_NAME_IS_UNKNOWN_SHAPE, true);
8962+ SetSubGraph(root_graph, known_node1, compute_graph1);
8963+ SetSubGraph(root_graph, known_node2, compute_graph2);
8964+ AddCompileResult(known_node1, false);
8965+ AddCompileResult(known_node2, false);
8966+ 
8967+ std::map<AscendString, AscendString> options;
8968+ Session session(options);
8969+ session.AddGraph(1U, graph);
8970+ EXPECT_EQ(session.CompileGraph(1U), SUCCESS);
8971+ RunAndVerify(session, 1U, root_graph, runtime_stub);
8972+}
8973+ 
8793} // namespace ge8974} // namespace ge
@@ -307,6 +307,7 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl) {
307}307}
308 308 
309TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_rts) {309TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_rts) {
310+ ge::GetThreadLocalContext().SetGraphOption({{"ge.featureBaseRefreshable", "1"}});
310 auto root_builder = block_mem_ut::GraphBuilder("root_graph");311 auto root_builder = block_mem_ut::GraphBuilder("root_graph");
311 const auto &data = root_builder.AddNode("data", DATA, 0, 1);312 const auto &data = root_builder.AddNode("data", DATA, 0, 1);
312 const auto &rts = root_builder.AddNode("STREAMSWITCH", STREAMSWITCH, 1, 1);313 const auto &rts = root_builder.AddNode("STREAMSWITCH", STREAMSWITCH, 1, 1);
@@ -325,15 +326,17 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_rts) {
325 ge::GetThreadLocalContext().SetGraphOption({{}});326 ge::GetThreadLocalContext().SetGraphOption({{}});
326}327}
327 328 
328-TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_refreshable_unsupport_hccl) {329+TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_static_graph_support_hccl) {
329 auto root_builder = block_mem_ut::GraphBuilder("root_graph");330 auto root_builder = block_mem_ut::GraphBuilder("root_graph");
330 ge::GetThreadLocalContext().SetGraphOption({{"ge.featureBaseRefreshable", "1"}});331 ge::GetThreadLocalContext().SetGraphOption({{"ge.featureBaseRefreshable", "1"}});
331- const auto &add = root_builder.AddNode("add", ADD, 0, 1);332+ const auto &data = root_builder.AddNode("data", DATA, 0, 1);
333+ const auto &hcom = root_builder.AddNode("hcom", HCOMALLREDUCE, 1, 1);
332 const auto &netout = root_builder.AddNode("NETOUTPUT", NETOUTPUT, 1, 1);334 const auto &netout = root_builder.AddNode("NETOUTPUT", NETOUTPUT, 1, 1);
333- root_builder.AddDataEdge(add, 0, netout, 0);335+ root_builder.AddDataEdge(data, 0, hcom, 0);
336+ root_builder.AddDataEdge(hcom, 0, netout, 0);
334 const auto &root_graph = root_builder.GetGraph();337 const auto &root_graph = root_builder.GetGraph();
335 338 
336- auto op_desc = root_graph->FindNode("add")->GetOpDesc();339+ auto op_desc = root_graph->FindNode("hcom")->GetOpDesc();
337 op_desc->SetOpKernelLibName(ge::kEngineNameHccl.c_str());340 op_desc->SetOpKernelLibName(ge::kEngineNameHccl.c_str());
338 341 
339 MemAssistInfo mem_assist_info;342 MemAssistInfo mem_assist_info;
@@ -341,7 +344,8 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_refreshable_unsupport_hccl) {
341 auto ret = GraphUtils::GetRefMapping(root_graph, mem_assist_info.symbol_to_anchors, mem_assist_info.anchor_to_symbol);344 auto ret = GraphUtils::GetRefMapping(root_graph, mem_assist_info.symbol_to_anchors, mem_assist_info.anchor_to_symbol);
342 EXPECT_EQ(ret, SUCCESS);345 EXPECT_EQ(ret, SUCCESS);
343 auto p1 = std::make_shared<FakBlockMemAssigner>(mem_assist_info);346 auto p1 = std::make_shared<FakBlockMemAssigner>(mem_assist_info);
344- EXPECT_EQ(p1->IsZeroCopyBlock(add, 0, false), false);347+ EXPECT_EQ(p1->IsZeroCopyBlock(hcom, 0, false), true);
348+ EXPECT_EQ(p1->IsZeroCopyBlock(data, 0, false), true);
345 ge::GetThreadLocalContext().SetGraphOption({{}});349 ge::GetThreadLocalContext().SetGraphOption({{}});
346}350}
347 351 
@@ -354,10 +358,10 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl_dynamic_static_subg
354 358 
355 auto sub_builder = std::make_shared<block_mem_ut::GraphBuilder>("sub_graph");359 auto sub_builder = std::make_shared<block_mem_ut::GraphBuilder>("sub_graph");
356 const auto &data = sub_builder->AddNode("data", DATA, 0, 1);360 const auto &data = sub_builder->AddNode("data", DATA, 0, 1);
357- const auto &add = sub_builder->AddNode("add", ADD, 1, 1);361+ const auto &hcom = sub_builder->AddNode("hcom", HCOMALLREDUCE, 1, 1);
358 const auto &netout = sub_builder->AddNode("NETOUTPUT", NETOUTPUT, 1, 1);362 const auto &netout = sub_builder->AddNode("NETOUTPUT", NETOUTPUT, 1, 1);
359- sub_builder->AddDataEdge(data, 0, add, 0);363+ sub_builder->AddDataEdge(data, 0, hcom, 0);
360- sub_builder->AddDataEdge(add, 0, netout, 0);364+ sub_builder->AddDataEdge(hcom, 0, netout, 0);
361 const auto &sub_graph = sub_builder->GetGraph();365 const auto &sub_graph = sub_builder->GetGraph();
362 366 
363 partitioned_call->GetOpDesc()->AddSubgraphName(sub_graph->GetName());367 partitioned_call->GetOpDesc()->AddSubgraphName(sub_graph->GetName());
@@ -366,7 +370,7 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl_dynamic_static_subg
366 sub_graph->SetParentNode(partitioned_call);370 sub_graph->SetParentNode(partitioned_call);
367 root_graph->AddSubgraph(sub_graph);371 root_graph->AddSubgraph(sub_graph);
368 372 
369- auto op_desc = sub_graph->FindNode("add")->GetOpDesc();373+ auto op_desc = sub_graph->FindNode("hcom")->GetOpDesc();
370 op_desc->SetOpKernelLibName(ge::kEngineNameHccl.c_str());374 op_desc->SetOpKernelLibName(ge::kEngineNameHccl.c_str());
371 375 
372 MemAssistInfo mem_assist_info;376 MemAssistInfo mem_assist_info;
@@ -374,8 +378,10 @@ TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl_dynamic_static_subg
374 auto ret = GraphUtils::GetRefMapping(sub_graph, mem_assist_info.symbol_to_anchors, mem_assist_info.anchor_to_symbol);378 auto ret = GraphUtils::GetRefMapping(sub_graph, mem_assist_info.symbol_to_anchors, mem_assist_info.anchor_to_symbol);
375 EXPECT_EQ(ret, SUCCESS);379 EXPECT_EQ(ret, SUCCESS);
376 auto p1 = std::make_shared<FakBlockMemAssigner>(mem_assist_info);380 auto p1 = std::make_shared<FakBlockMemAssigner>(mem_assist_info);
377- EXPECT_EQ(p1->IsZeroCopyBlock(add, 0, false), false);381+ // data support zero copy
382+ // net out not support zero copy
378 EXPECT_EQ(p1->IsZeroCopyBlock(data, 0, false), true);383 EXPECT_EQ(p1->IsZeroCopyBlock(data, 0, false), true);
384+ EXPECT_EQ(p1->IsZeroCopyBlock(hcom, 0, false), false);
379}385}
380 386 
381TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl_with_dynamic) {387TEST_F(UtestBlockMemAssigner, IsZeroCopyBlock_unsupport_hccl_with_dynamic) {
@@ -1153,13 +1159,11 @@ TEST_F(UtestBlockMemAssigner, ContinuousOutputCanNotZeroCpy) {
1153 MemoryBlock child(reuse_strategy_, block_size, stream_id, is_reuse_mem, memory_type);1159 MemoryBlock child(reuse_strategy_, block_size, stream_id, is_reuse_mem, memory_type);
1154 child.is_reuse_zero_copy_ = true;1160 child.is_reuse_zero_copy_ = true;
1155 child.is_zero_copy_ = true;1161 child.is_zero_copy_ = true;
1156- MarkReuseZeroCopyBlockFlag(node_a, &child, 0, false);1162+ MarkReuseZeroCopyBlockFlag(node_a, &child, 0);
1157 EXPECT_EQ(child.is_reuse_zero_copy_, false);1163 EXPECT_EQ(child.is_reuse_zero_copy_, false);
1158- EXPECT_EQ(child.is_zero_copy_, true);
1159 1164 
1160- MarkReuseZeroCopyBlockFlag(node, &child, 0, false);1165+ MarkReuseZeroCopyBlockFlag(node, &child, 0);
1161 EXPECT_EQ(child.is_reuse_zero_copy_, false);1166 EXPECT_EQ(child.is_reuse_zero_copy_, false);
1162- EXPECT_EQ(child.is_zero_copy_, false);
1163}1167}
1164 1168 
1165TEST_F(UtestBlockMemAssigner, DataOutDiffStream) {1169TEST_F(UtestBlockMemAssigner, DataOutDiffStream) {