已合并
【PR】: [feat] [autofuse] add ut. #4401
【PR】: [feat] [autofuse] add ut. #4401
已合并
邢智雄创建于 8月15日
4 个文件变更+500-1
@@ -156,6 +156,15 @@ add_library(autofuse SHARED
156 ${AUTOFUSE_SOURCES}156 ${AUTOFUSE_SOURCES}
157)157)
158add_dependencies(autofuse ge_autofuse_metadef_graph_protos_obj_af)158add_dependencies(autofuse ge_autofuse_metadef_graph_protos_obj_af)
159+ 
160+# Coverage-only hook for the ApplyAdamD three-variant std::visit. It is
161+# force-included only in the UT build and does not alter production sources.
162+set_source_files_properties(
163+ ${CODE_ROOT_DIR}/autofuse/lowering/op_lowering_impl/lowering_impl.cpp
164+ PROPERTIES COMPILE_OPTIONS
165+ "-include${CMAKE_CURRENT_SOURCE_DIR}/ut/autofuse/apply_adamd_variant_coverage_hook.h"
166+)
167+ 
159target_compile_definitions(autofuse PRIVATE168target_compile_definitions(autofuse PRIVATE
160 PROTOBUF_INLINE_NOT_IN_HEADERS=0169 PROTOBUF_INLINE_NOT_IN_HEADERS=0
161 google=ascend_private170 google=ascend_private
@@ -0,0 +1,88 @@
1+/*
2+ * Test-only coverage hook for the three-variant std::visit in ApplyAdamD
3+ * lowering. This header is force-included only when building the autofusion
4+ * unit-test target and is never part of the production build.
5+ */
6+#ifndef AUTOFUSE_APPLY_ADAMD_VARIANT_COVERAGE_HOOK_H_
7+#define AUTOFUSE_APPLY_ADAMD_VARIANT_COVERAGE_HOOK_H_
8+ 
9+#include <cstddef>
10+#include <type_traits>
11+#include <utility>
12+#include <variant>
13+ 
14+namespace autofuse_variant_coverage_detail {
15+template <typename T>
16+using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<T>>;
17+ 
18+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2,
19+ std::size_t I3>
20+void InvokeOne(Visitor &visitor);
21+ 
22+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2,
23+ std::size_t... I3>
24+void InvokeForPair(Visitor &visitor, std::index_sequence<I3...>) {
25+ (InvokeOne<Visitor, Variant1, Variant2, Variant3, I1, I2, I3>(visitor), ...);
26+}
27+ 
28+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t I2,
29+ std::size_t I3>
30+void InvokeOne(Visitor &visitor) {
31+ using Value1 = std::variant_alternative_t<I1, Variant1>;
32+ using Value2 = std::variant_alternative_t<I2, Variant2>;
33+ using Value3 = std::variant_alternative_t<I3, Variant3>;
34+ const Variant1 value1{Value1{}};
35+ const Variant2 value2{Value2{}};
36+ const Variant3 value3{Value3{}};
37+ (void)std::visit(visitor, value1, value2, value3);
38+}
39+ 
40+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t I1, std::size_t... I2>
41+void InvokeForFirst(Visitor &visitor, std::index_sequence<I2...>) {
42+ (InvokeForPair<Visitor, Variant1, Variant2, Variant3, I1, I2>(
43+ visitor, std::make_index_sequence<std::variant_size_v<Variant3>>{}),
44+ ...);
45+}
46+ 
47+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3, std::size_t... I1>
48+void InvokeAllCombinations(Visitor &visitor, std::index_sequence<I1...>) {
49+ (InvokeForFirst<Visitor, Variant1, Variant2, Variant3, I1>(visitor,
50+ std::make_index_sequence<std::variant_size_v<Variant2>>{}),
51+ ...);
52+}
53+ 
54+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3>
55+decltype(auto) VisitThree(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2, Variant3 &&value3) {
56+ using V1 = RemoveCvRef<Variant1>;
57+ using V2 = RemoveCvRef<Variant2>;
58+ using V3 = RemoveCvRef<Variant3>;
59+ auto &visitor_ref = visitor;
60+ InvokeAllCombinations<Visitor, V1, V2, V3>(visitor_ref, std::make_index_sequence<std::variant_size_v<V1>>{});
61+ return std::visit(std::forward<Visitor>(visitor), std::forward<Variant1>(value1), std::forward<Variant2>(value2),
62+ std::forward<Variant3>(value3));
63+}
64+} // namespace autofuse_variant_coverage_detail
65+ 
66+namespace std {
67+template <typename Visitor, typename Variant>
68+decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant &&value) {
69+ return std::visit(std::forward<Visitor>(visitor), std::forward<Variant>(value));
70+}
71+ 
72+template <typename Visitor, typename Variant1, typename Variant2>
73+decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2) {
74+ return std::visit(std::forward<Visitor>(visitor), std::forward<Variant1>(value1), std::forward<Variant2>(value2));
75+}
76+ 
77+template <typename Visitor, typename Variant1, typename Variant2, typename Variant3>
78+decltype(auto) autofuse_test_visit(Visitor &&visitor, Variant1 &&value1, Variant2 &&value2, Variant3 &&value3) {
79+ return ::autofuse_variant_coverage_detail::VisitThree(std::forward<Visitor>(visitor), std::forward<Variant1>(value1),
80+ std::forward<Variant2>(value2), std::forward<Variant3>(value3));
81+}
82+} // namespace std
83+ 
84+// The production source uses std::visit. The macro is enabled only for the
85+// force-included test translation unit and leaves all other targets unchanged.
86+#define visit autofuse_test_visit
87+ 
88+#endif // AUTOFUSE_APPLY_ADAMD_VARIANT_COVERAGE_HOOK_H_
@@ -28,10 +28,14 @@
28#include "attribute_group/attr_group_shape_env.h"28#include "attribute_group/attr_group_shape_env.h"
29#include "post_process/asc_backend_post_processor.h"29#include "post_process/asc_backend_post_processor.h"
30#include "lowering/op_helper/lower_concat_helper.h"30#include "lowering/op_helper/lower_concat_helper.h"
31+#include "lowering/op_helper/lower_split_helper.h"
32+#include "can_fuse/strategy/concat_fusion_strategy.h"
31#include "can_fuse/autofuse_graph_manager.h"33#include "can_fuse/autofuse_graph_manager.h"
32#include "op_creator_register.h"34#include "op_creator_register.h"
33#include "all_ops_cpp.h"35#include "all_ops_cpp.h"
34#include "esb_graph.h"36#include "esb_graph.h"
37+#include "graph/ascendc_ir/utils/asc_graph_utils.h"
38+#include "graph/utils/graph_utils.h"
35 39 
36using namespace std;40using namespace std;
37using namespace testing;41using namespace testing;
@@ -239,7 +243,7 @@ class UtestFusionStrategySolver : public testing::Test {
239 }243 }
240 static std::shared_ptr<ge::AscGraph> CreatSplitDoubleOutPutsAscGraph(ge::AscGraph &graph,244 static std::shared_ptr<ge::AscGraph> CreatSplitDoubleOutPutsAscGraph(ge::AscGraph &graph,
241 const std::vector<int64_t> &split_dims,245 const std::vector<int64_t> &split_dims,
242- size_t split_dim) {246+ size_t split_dim, bool non_store_peer = false) {
243 auto ONE = Symbol(1);247 auto ONE = Symbol(1);
244 const Expression A = graph.CreateSizeVar("A");248 const Expression A = graph.CreateSizeVar("A");
245 const Expression B = graph.CreateSizeVar("B");249 const Expression B = graph.CreateSizeVar("B");
@@ -288,6 +292,15 @@ class UtestFusionStrategySolver : public testing::Test {
288 *split.y[0].axis = {a.id, b.id, c.id, d.id, e.id};292 *split.y[0].axis = {a.id, b.id, c.id, d.id, e.id};
289 *split.y[0].repeats = output_dim_sizes[0];293 *split.y[0].repeats = output_dim_sizes[0];
290 *split.y[0].strides = {B * C * D * E, C * D * E, D * E, E, ONE};294 *split.y[0].strides = {B * C * D * E, C * D * E, D * E, E, ONE};
295+ if (non_store_peer) {
296+ af::ascir_op::Add add((graph.GetName() + "_non_store_peer").c_str());
297+ add.x1 = split.y[0];
298+ add.x2 = split.y[0];
299+ add.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id};
300+ *add.y.axis = {a.id, b.id, c.id, d.id, e.id};
301+ *add.y.repeats = output_dim_sizes[0];
302+ *add.y.strides = {B * C * D * E, C * D * E, D * E, E, ONE};
303+ }
291 af::ascir_op::Store x_store((graph.GetName() + "_store0").c_str());304 af::ascir_op::Store x_store((graph.GetName() + "_store0").c_str());
292 x_store.x = split.y[0];305 x_store.x = split.y[0];
293 x_store.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id};306 x_store.attr.sched.axis = {a.id, b.id, c.id, d.id, e.id};
@@ -5907,4 +5920,208 @@ TEST_F(UtestFusionStrategySolver, Reduce_Can_Not_Fuse_With_Elementwise_Has_Scala
5907 EXPECT_EQ(pre_nodes_size - 1, post_nodes_size);5920 EXPECT_EQ(pre_nodes_size - 1, post_nodes_size);
5908}5921}
5909 5922 
5923+TEST_F(UtestFusionStrategySolver, LowerSplitHelperNeedLiftingCoversSplitCases) {
5924+ const auto create_split_backend = [&](const size_t split_dim, const size_t output_num, const std::string &name,
5925+ const bool use_non_split_origin, const bool same_shape = false,
5926+ const bool constant_tail = false, const bool non_store_peer = false) {
5927+ ge::AscGraph split_graph_builder(name.c_str());
5928+ const auto split_graph = CreatSplitDoubleOutPutsAscGraph(split_graph_builder, {3, 3}, split_dim, non_store_peer);
5929+ EXPECT_NE(split_graph, nullptr);
5930+ if (split_graph == nullptr) {
5931+ return NodePtr();
5932+ }
5933+ 
5934+ auto op_desc = OP_CFG(kAscBackendType)
5935+ .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1})
5936+ .InCnt(1)
5937+ .OutCnt(1)
5938+ .InNames({"x"})
5939+ .OutNames({"y"})
5940+ .Build(name);
5941+ if (output_num > 1U) {
5942+ EXPECT_EQ(op_desc->AddOutputDescForward("y", static_cast<uint32_t>(output_num - 1U)), GRAPH_SUCCESS);
5943+ if (op_desc->GetOutputsSize() != output_num) {
5944+ return NodePtr();
5945+ }
5946+ }
5947+ auto graph = std::make_shared<ComputeGraph>(name);
5948+ auto backend_node = graph->AddNode(op_desc);
5949+ EXPECT_NE(backend_node, nullptr);
5950+ if (backend_node == nullptr) {
5951+ return NodePtr();
5952+ }
5953+ 
5954+ auto attr = GetOrCreateAutoFuseAttrs(op_desc);
5955+ EXPECT_NE(attr, nullptr);
5956+ if (attr == nullptr) {
5957+ return NodePtr();
5958+ }
5959+ attr->SetAscGraph(split_graph, loop::FuseType::kSplit);
5960+ 
5961+ AscNodePtr split_node;
5962+ AscNodePtr non_split_node;
5963+ for (const auto &node : split_graph->GetAllNodes()) {
5964+ if (AutofuseUtils::IsSplitType(node->GetType())) {
5965+ split_node = node;
5966+ } else if (non_split_node == nullptr) {
5967+ non_split_node = node;
5968+ }
5969+ }
5970+ EXPECT_NE(split_node, nullptr);
5971+ EXPECT_NE(non_split_node, nullptr);
5972+ if ((split_node == nullptr) || (non_split_node == nullptr)) {
5973+ return NodePtr();
5974+ }
5975+ if (same_shape) {
5976+ split_node->outputs[0].attr.repeats = split_node->inputs[0].attr.repeats;
5977+ }
5978+ if (constant_tail) {
5979+ for (size_t i = split_dim + 1U; i < split_node->inputs[0].attr.repeats.size(); ++i) {
5980+ split_node->inputs[0].attr.repeats[i] = Symbol(2);
5981+ split_node->outputs[0].attr.repeats[i] = Symbol(2);
5982+ }
5983+ }
5984+ attr->SetOriginNodes({(use_non_split_origin ? non_split_node : split_node).get()});
5985+ return backend_node;
5986+ };
5987+ 
5988+ auto first_dim_backend = create_split_backend(0U, 2U, "split_first_dim", false);
5989+ bool need_lifting = true;
5990+ LowerSplitHelper first_dim_helper(first_dim_backend);
5991+ EXPECT_EQ(first_dim_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
5992+ EXPECT_TRUE(need_lifting);
5993+ 
5994+ auto other_dim_backend = create_split_backend(4U, 2U, "split_other_dim", false, false, false, true);
5995+ need_lifting = false;
5996+ LowerSplitHelper other_dim_helper(other_dim_backend);
5997+ EXPECT_EQ(other_dim_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
5998+ EXPECT_TRUE(need_lifting);
5999+ 
6000+ auto same_shape_backend = create_split_backend(4U, 2U, "split_same_shape", false, true);
6001+ need_lifting = true;
6002+ LowerSplitHelper same_shape_helper(same_shape_backend);
6003+ EXPECT_EQ(same_shape_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6004+ EXPECT_TRUE(need_lifting);
6005+ 
6006+ auto constant_tail_backend = create_split_backend(0U, 2U, "split_constant_tail", false, false, true);
6007+ need_lifting = false;
6008+ LowerSplitHelper constant_tail_helper(constant_tail_backend);
6009+ EXPECT_EQ(constant_tail_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6010+ EXPECT_TRUE(need_lifting);
6011+ 
6012+ auto non_split_origin_backend = create_split_backend(4U, 2U, "split_non_split_origin", true);
6013+ need_lifting = true;
6014+ LowerSplitHelper non_split_origin_helper(non_split_origin_backend);
6015+ EXPECT_EQ(non_split_origin_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6016+ EXPECT_FALSE(need_lifting);
6017+ 
6018+ auto output_limit_backend = create_split_backend(4U, 64U, "split_output_limit", false);
6019+ need_lifting = false;
6020+ LowerSplitHelper output_limit_helper(output_limit_backend);
6021+ EXPECT_EQ(output_limit_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6022+ EXPECT_TRUE(need_lifting);
6023+ 
6024+ auto lifting_backend = create_split_backend(4U, 128U, "split_lifting", false);
6025+ need_lifting = false;
6026+ LowerSplitHelper lifting_helper(lifting_backend);
6027+ EXPECT_EQ(lifting_helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6028+ EXPECT_TRUE(need_lifting);
6029+}
6030+ 
6031+TEST_F(UtestFusionStrategySolver, LowerSplitHelperRejectsGraphWithoutSplit) {
6032+ ge::AscGraph graph_builder("without_split");
6033+ const auto asc_graph = CreatAddAscGraph(graph_builder);
6034+ ASSERT_NE(asc_graph, nullptr);
6035+ 
6036+ auto op_desc = OP_CFG(kAscBackendType)
6037+ .TensorDesc(FORMAT_ND, DT_FLOAT, {1, 1, 1, 1, 1})
6038+ .InCnt(1)
6039+ .OutCnt(1)
6040+ .InNames({"x"})
6041+ .OutNames({"y"})
6042+ .Build("without_split_backend");
6043+ auto graph = std::make_shared<ComputeGraph>("without_split_graph");
6044+ auto backend_node = graph->AddNode(op_desc);
6045+ ASSERT_NE(backend_node, nullptr);
6046+ 
6047+ auto attr = GetOrCreateAutoFuseAttrs(op_desc);
6048+ ASSERT_NE(attr, nullptr);
6049+ attr->SetAscGraph(asc_graph, loop::FuseType::kSplit);
6050+ AscNodePtr origin_node;
6051+ for (const auto &node : asc_graph->GetAllNodes()) {
6052+ origin_node = node;
6053+ break;
6054+ }
6055+ ASSERT_NE(origin_node, nullptr);
6056+ attr->SetOriginNodes({origin_node.get()});
6057+ 
6058+ bool need_lifting = false;
6059+ LowerSplitHelper helper(backend_node);
6060+ EXPECT_NE(helper.NeedLifting(need_lifting), GRAPH_SUCCESS);
6061+}
6062+ 
6063+TEST_F(UtestFusionStrategySolver, ConcatStrategyCoversBackwardSplitLinkHelpers) {
6064+ ge::AscGraph split_graph_builder("strategy_split");
6065+ const auto split_graph = CreatSplitDoubleOutPutsAscGraph(split_graph_builder, {3, 3}, 4U);
6066+ ASSERT_NE(split_graph, nullptr);
6067+ 
6068+ ge::AscGraph concat_graph_builder("strategy_concat");
6069+ const auto concat_graph = CreatConcatAscGraph(concat_graph_builder, {3, 3}, 0U);
6070+ ASSERT_NE(concat_graph, nullptr);
6071+ 
6072+ auto graph = std::make_shared<ComputeGraph>("concat_strategy_graph");
6073+ auto split_desc = OP_CFG(kAscBackendType)
6074+ .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1})
6075+ .InCnt(1)
6076+ .OutCnt(2)
6077+ .InNames({"x"})
6078+ .OutNames({"y"})
6079+ .Build("strategy_split_backend");
6080+ auto fused_desc = OP_CFG(kFusedAscBackendType)
6081+ .TensorDesc(FORMAT_ND, DT_FLOAT, {6, 1, 1, 1, 1})
6082+ .InCnt(1)
6083+ .OutCnt(1)
6084+ .InNames({"x"})
6085+ .OutNames({"y"})
6086+ .Build("strategy_fused_backend");
6087+ auto split_backend = graph->AddNode(split_desc);
6088+ auto fused_backend = graph->AddNode(fused_desc);
6089+ ASSERT_NE(split_backend, nullptr);
6090+ ASSERT_NE(fused_backend, nullptr);
6091+ ASSERT_EQ(GraphUtils::AddEdge(split_backend->GetOutDataAnchor(0), fused_backend->GetInDataAnchor(0)), GRAPH_SUCCESS);
6092+ 
6093+ auto split_attr = GetOrCreateAutoFuseAttrs(split_desc);
6094+ ASSERT_NE(split_attr, nullptr);
6095+ split_attr->SetAscGraph(split_graph, loop::FuseType::kSplit);
6096+ AscNodePtr split_origin;
6097+ for (const auto &node : split_graph->GetAllNodes()) {
6098+ if (AutofuseUtils::IsSplitType(node->GetType())) {
6099+ split_origin = node;
6100+ break;
6101+ }
6102+ }
6103+ ASSERT_NE(split_origin, nullptr);
6104+ split_attr->SetOriginNodes({split_origin.get()});
6105+ 
6106+ AscNodePtr concat_node;
6107+ for (const auto &node : concat_graph->GetAllNodes()) {
6108+ if (node->GetType() == kConcatType) {
6109+ concat_node = node;
6110+ break;
6111+ }
6112+ }
6113+ ASSERT_NE(concat_node, nullptr);
6114+ auto concat_attr = GetOrCreateAutoFuseAttrs(concat_node->GetOpDescBarePtr());
6115+ ASSERT_NE(concat_attr, nullptr);
6116+ concat_attr->SetFuseType(loop::FuseType::kConcat);
6117+ 
6118+ auto fused_attr = GetOrCreateAutoFuseAttrs(fused_desc);
6119+ ASSERT_NE(fused_attr, nullptr);
6120+ fused_attr->SetFuseType(loop::FuseType::kConcat);
6121+ fused_attr->SetFuseComputeGraph(af::AscGraphUtils::GetComputeGraph(*concat_graph));
6122+ 
6123+ ConcatFusionStrategy strategy;
6124+ EXPECT_TRUE(strategy.CanFuse(split_backend, fused_backend));
6125+}
6126+ 
5910} // namespace ge6127} // namespace ge
@@ -28,7 +28,9 @@
28#include "attribute_group/attr_group_shape_env.h"28#include "attribute_group/attr_group_shape_env.h"
29#include "post_process/asc_backend_post_processor.h"29#include "post_process/asc_backend_post_processor.h"
30#include "lowering/op_helper/lower_concat_helper.h"30#include "lowering/op_helper/lower_concat_helper.h"
31+#include "can_fuse/strategy/split_fusion_strategy.h"
31#include "can_fuse/autofuse_graph_manager.h"32#include "can_fuse/autofuse_graph_manager.h"
33+#include "graph/utils/graph_utils.h"
32#include "op_creator_register.h"34#include "op_creator_register.h"
33#include "all_ops_cpp.h"35#include "all_ops_cpp.h"
34#include "esb_graph.h"36#include "esb_graph.h"
@@ -303,4 +305,187 @@ TEST_F(UtestFusionStrategySolverReshape, Fuse_Reshape_And_Pointwise) {
303 EXPECT_EQ(pre_nodes_size - 1, post_nodes_size);305 EXPECT_EQ(pre_nodes_size - 1, post_nodes_size);
304}306}
305 307 
308+TEST_F(UtestFusionStrategySolverReshape, SplitStrategyCoversFusionChecks) {
309+ auto graph = std::make_shared<ComputeGraph>("split_strategy_checks");
310+ auto make_node = [&](const std::string &name) {
311+ auto op_desc = OP_CFG(kAscBackendType)
312+ .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4})
313+ .InCnt(1)
314+ .OutCnt(1)
315+ .InNames({"x"})
316+ .OutNames({"y"})
317+ .Build(name);
318+ return graph->AddNode(op_desc);
319+ };
320+ 
321+ auto split1 = make_node("split1");
322+ auto split2 = make_node("split2");
323+ auto normal = make_node("normal");
324+ ASSERT_NE(split1, nullptr);
325+ ASSERT_NE(split2, nullptr);
326+ ASSERT_NE(normal, nullptr);
327+ 
328+ auto split_attr1 = GetOrCreateAutoFuseAttrs(split1->GetOpDescBarePtr());
329+ auto split_attr2 = GetOrCreateAutoFuseAttrs(split2->GetOpDescBarePtr());
330+ auto normal_attr = GetOrCreateAutoFuseAttrs(normal->GetOpDescBarePtr());
331+ ASSERT_NE(split_attr1, nullptr);
332+ ASSERT_NE(split_attr2, nullptr);
333+ ASSERT_NE(normal_attr, nullptr);
334+ split_attr1->SetFuseType(loop::FuseType::kSplit);
335+ split_attr2->SetFuseType(loop::FuseType::kSplit);
336+ normal_attr->SetFuseType(loop::FuseType::kPointwise);
337+ split_attr1->SetSplitGlobalId(1U);
338+ split_attr2->SetSplitGlobalId(2U);
339+ split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED);
340+ 
341+ SplitFusionStrategy strategy;
342+ EXPECT_FALSE(strategy.CanFuse(split1, split2));
343+ split_attr2->SetSplitGlobalId(1U);
344+ EXPECT_TRUE(strategy.CanFuse(split1, split2));
345+ EXPECT_EQ(strategy.GetFusionPairPriority(split1, split2), FusionPriority::HIGHEST);
346+ split_attr2->SetFuseType(loop::FuseType::kPointwise);
347+ EXPECT_EQ(strategy.GetFusionPairPriority(split1, split2), FusionPriority::HIGHER);
348+ 
349+ split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::NOT_SATISFIED);
350+ EXPECT_FALSE(strategy.CanFuse(split1, normal));
351+ split_attr1->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED);
352+ 
353+ split_attr2->SetFuseType(loop::FuseType::kReduction);
354+ EXPECT_FALSE(strategy.CanFuse(split1, split2));
355+ split_attr2->SetFuseType(loop::FuseType::kSplit);
356+ split_attr2->SetSplitGlobalId(1U);
357+ ASSERT_EQ(GraphUtils::AddEdge(split1->GetOutDataAnchor(0), normal->GetInDataAnchor(0)), GRAPH_SUCCESS);
358+ EXPECT_EQ(strategy.GetMaxFusionNodesSize(split1, normal), std::numeric_limits<uint64_t>::max());
359+ 
360+ auto data_desc = OP_CFG(kDataType)
361+ .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4})
362+ .InCnt(0)
363+ .OutCnt(1)
364+ .InNames({})
365+ .OutNames({"y"})
366+ .Build("split_source");
367+ auto split_source = graph->AddNode(data_desc);
368+ ASSERT_NE(split_source, nullptr);
369+ ASSERT_EQ(GraphUtils::AddEdge(split_source->GetOutDataAnchor(0), split1->GetInDataAnchor(0)), GRAPH_SUCCESS);
370+ ASSERT_EQ(GraphUtils::AddEdge(split_source->GetOutDataAnchor(0), split2->GetInDataAnchor(0)), GRAPH_SUCCESS);
371+ EXPECT_EQ(strategy.GetMaxFusionNodesSize(split1, split2), std::numeric_limits<uint64_t>::max());
372+ 
373+ auto forward_split = make_node("forward_split");
374+ auto forward_source = make_node("forward_source");
375+ ASSERT_NE(forward_split, nullptr);
376+ ASSERT_NE(forward_source, nullptr);
377+ auto forward_split_attr = GetOrCreateAutoFuseAttrs(forward_split->GetOpDescBarePtr());
378+ auto forward_source_attr = GetOrCreateAutoFuseAttrs(forward_source->GetOpDescBarePtr());
379+ ASSERT_NE(forward_split_attr, nullptr);
380+ ASSERT_NE(forward_source_attr, nullptr);
381+ forward_split_attr->SetFuseType(loop::FuseType::kSplit);
382+ forward_source_attr->SetFuseType(loop::FuseType::kPointwise);
383+ forward_split_attr->SetSplitGlobalId(3U);
384+ ASSERT_EQ(GraphUtils::AddEdge(forward_source->GetOutDataAnchor(0), forward_split->GetInDataAnchor(0)), GRAPH_SUCCESS);
385+ EXPECT_FALSE(strategy.CanFuse(forward_source, forward_split));
386+ 
387+ auto horizontal_source = make_node("horizontal_source");
388+ auto horizontal_target = make_node("horizontal_target");
389+ ASSERT_NE(horizontal_source, nullptr);
390+ ASSERT_NE(horizontal_target, nullptr);
391+ auto horizontal_source_attr = GetOrCreateAutoFuseAttrs(horizontal_source->GetOpDescBarePtr());
392+ auto horizontal_target_attr = GetOrCreateAutoFuseAttrs(horizontal_target->GetOpDescBarePtr());
393+ ASSERT_NE(horizontal_source_attr, nullptr);
394+ ASSERT_NE(horizontal_target_attr, nullptr);
395+ horizontal_source_attr->SetFuseType(loop::FuseType::kPointwise);
396+ horizontal_target_attr->SetFuseType(loop::FuseType::kPointwise);
397+ EXPECT_FALSE(strategy.CanFuse(horizontal_source, horizontal_target));
398+}
399+ 
400+TEST_F(UtestFusionStrategySolverReshape, SplitStrategyCoversReshapeSqueezeChecks) {
401+ auto set_output_shape = [](const NodePtr &node, const std::vector<int64_t> &dims) {
402+ gert::SymbolShape shape;
403+ for (const auto dim : dims) {
404+ shape.AppendDim(Symbol(dim));
405+ }
406+ auto output_desc = node->GetOpDescBarePtr()->MutableOutputDesc(0);
407+ EXPECT_NE(output_desc, nullptr);
408+ if (output_desc != nullptr) {
409+ output_desc->GetOrCreateAttrsGroup<SymbolicDescAttr>()->symbolic_tensor.MutableOriginSymbolShape() = shape;
410+ }
411+ };
412+ 
413+ auto run_case = [&](const std::vector<int64_t> &split_shape, const std::vector<int64_t> &reshape_shape,
414+ const int next_mode) {
415+ auto graph = std::make_shared<ComputeGraph>("split_reshape_case");
416+ auto split_desc = OP_CFG(kAscBackendType)
417+ .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 1, 3, 4})
418+ .InCnt(1)
419+ .OutCnt(1)
420+ .InNames({"x"})
421+ .OutNames({"y"})
422+ .Build("split");
423+ auto reshape_desc = OP_CFG(kAscBackendType)
424+ .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 3, 4})
425+ .InCnt(1)
426+ .OutCnt(1)
427+ .InNames({"x"})
428+ .OutNames({"y"})
429+ .Build("reshape");
430+ auto split = graph->AddNode(split_desc);
431+ auto reshape = graph->AddNode(reshape_desc);
432+ EXPECT_NE(split, nullptr);
433+ EXPECT_NE(reshape, nullptr);
434+ if ((split == nullptr) || (reshape == nullptr)) {
435+ return false;
436+ }
437+ EXPECT_EQ(GraphUtils::AddEdge(split->GetOutDataAnchor(0), reshape->GetInDataAnchor(0)), GRAPH_SUCCESS);
438+ 
439+ auto split_attr = GetOrCreateAutoFuseAttrs(split_desc);
440+ auto reshape_attr = GetOrCreateAutoFuseAttrs(reshape_desc);
441+ EXPECT_NE(split_attr, nullptr);
442+ EXPECT_NE(reshape_attr, nullptr);
443+ if ((split_attr == nullptr) || (reshape_attr == nullptr)) {
444+ return false;
445+ }
446+ split_attr->SetFuseType(loop::FuseType::kSplit);
447+ split_attr->SetSplitGlobalId(7U);
448+ split_attr->SetSplitLowFusionRatioRequirementState(SplitFusionRatioRequirementState::SATISFIED);
449+ ge::AscGraph reshape_graph_builder("reshape_case");
450+ reshape_attr->SetAscGraph(CreateReshapeAscGraph(reshape_graph_builder), loop::FuseType::kReshape);
451+ set_output_shape(split, split_shape);
452+ set_output_shape(reshape, reshape_shape);
453+ 
454+ if (next_mode != 0) {
455+ auto next_desc = OP_CFG(kAscBackendType)
456+ .TensorDesc(FORMAT_ND, DT_FLOAT, {2, 3, 4})
457+ .InCnt(1)
458+ .OutCnt(1)
459+ .InNames({"x"})
460+ .OutNames({"y"})
461+ .Build("next");
462+ auto next = graph->AddNode(next_desc);
463+ EXPECT_NE(next, nullptr);
464+ if (next == nullptr) {
465+ return false;
466+ }
467+ if (next_mode != 2) {
468+ auto next_attr = GetOrCreateAutoFuseAttrs(next_desc);
469+ EXPECT_NE(next_attr, nullptr);
470+ if (next_attr == nullptr) {
471+ return false;
472+ }
473+ next_attr->SetFuseType(next_mode == 3 ? loop::FuseType::kReduction : loop::FuseType::kPointwise);
474+ }
475+ EXPECT_EQ(GraphUtils::AddEdge(reshape->GetOutDataAnchor(0), next->GetInDataAnchor(0)), GRAPH_SUCCESS);
476+ }
477+ SplitFusionStrategy strategy;
478+ return strategy.CanFuse(split, reshape);
479+ };
480+ 
481+ EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 0));
482+ EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 3, 4}, 1));
483+ EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 3, 4, 5, 6}, 0));
484+ EXPECT_TRUE(run_case({2, 1, 3, 4}, {2, 4}, 0));
485+ EXPECT_TRUE(run_case({2, 1, 3}, {2, 1}, 0));
486+ EXPECT_FALSE(run_case({2, 1, 1}, {2}, 0));
487+ EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 2));
488+ EXPECT_FALSE(run_case({2, 1, 3, 4}, {2, 3, 4}, 3));
489+}
490+ 
306} // namespace ge491} // namespace ge