已合并
【fix】: 修复重复声明output/dim_a && 修复Reduce多同输入节点断图逻辑问题 && 断图后group按照依赖关系重新排序 #1736
WangYanMale创建于 22 天前
【fix】: 修复重复声明output/dim_a && 修复Reduce多同输入节点断图逻辑问题 && 断图后group按照依赖关系重新排序 #1736
已合并
共 6 个文件变更+111-27
| @@ -503,7 +503,7 @@ void Loop::Destruct() { | |||
| 503 | } | 503 | } |
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | -void Loop::CollectTensorCrossLoop(std::map<ascir::AxisId, std::vector<ApiCall *>> &api_calls) { | 506 | +void Loop::CollectTensorCrossLoop(std::map<ascir::AxisId, std::map<Loop *, std::vector<ApiCall *>>> &api_calls) { |
| 507 | if (this->bodys.size() <= 1) { | 507 | if (this->bodys.size() <= 1) { |
| 508 | return; | 508 | return; |
| 509 | } | 509 | } |
| @@ -517,7 +517,7 @@ void Loop::CollectTensorCrossLoop(std::map<ascir::AxisId, std::vector<ApiCall *> | |||
| 517 | ascir::AxisId target_axis; | 517 | ascir::AxisId target_axis; |
| 518 | bool flag = inner_body.call->IsReadOutersideWrite(target_axis); | 518 | bool flag = inner_body.call->IsReadOutersideWrite(target_axis); |
| 519 | if (flag) { | 519 | if (flag) { |
| 520 | - api_calls[target_axis].emplace_back(inner_body.call); | 520 | + api_calls[target_axis][body.loop].emplace_back(inner_body.call); |
| 521 | } | 521 | } |
| 522 | } | 522 | } |
| 523 | } | 523 | } |
| @@ -585,11 +585,11 @@ static std::string GetCacheGuardCondition(const ApiCall &call, bool is_enable_ca | |||
| 585 | Status Loop::GenerateBody(const Tiler &tiler, const TPipe &tpipe, std::vector<ascir::AxisId> ¤t_axis, | 585 | Status Loop::GenerateBody(const Tiler &tiler, const TPipe &tpipe, std::vector<ascir::AxisId> ¤t_axis, |
| 586 | std::stringstream &ss) { | 586 | std::stringstream &ss) { |
| 587 | bool need_collect = this->bodys.size() > 1; | 587 | bool need_collect = this->bodys.size() > 1; |
| 588 | - std::map<ascir::AxisId, std::vector<ApiCall *>> api_calls_cross_loop; | 588 | + std::map<ascir::AxisId, std::map<Loop *, std::vector<ApiCall *>>> api_calls_cross_loop; |
| 589 | if (need_collect) { | 589 | if (need_collect) { |
| 590 | CollectTensorCrossLoop(api_calls_cross_loop); | 590 | CollectTensorCrossLoop(api_calls_cross_loop); |
| 591 | } | 591 | } |
| 592 | - auto target_calls = api_calls_cross_loop[this->axis_id]; | 592 | + auto &cross_loop_map = api_calls_cross_loop[this->axis_id]; |
| 593 | 593 | ||
| 594 | for (const auto &body : this->bodys) { | 594 | for (const auto &body : this->bodys) { |
| 595 | if ((body.type == LoopType::CALL) && (body.call->api_call_context.scene == ApiScene::kCVFuseUBLoad || | 595 | if ((body.type == LoopType::CALL) && (body.call->api_call_context.scene == ApiScene::kCVFuseUBLoad || |
| @@ -597,14 +597,19 @@ Status Loop::GenerateBody(const Tiler &tiler, const TPipe &tpipe, std::vector<as | |||
| 597 | continue; | 597 | continue; |
| 598 | } | 598 | } |
| 599 | if (body.type == LoopType::LOOP) { | 599 | if (body.type == LoopType::LOOP) { |
| 600 | - for (auto call : target_calls) { | 600 | + auto it = cross_loop_map.find(body.loop); |
| 601 | - GE_CHK_STATUS_RET(call->AllocOutputs(tpipe, ss), "Codegen alloc outputs failed"); | 601 | + if (it != cross_loop_map.end()) { |
| 602 | - used_calls.insert(call); | 602 | + for (auto call : it->second) { |
| 603 | + GE_CHK_STATUS_RET(call->AllocOutputs(tpipe, ss), "Codegen alloc outputs failed"); | ||
| 604 | + used_calls.insert(call); | ||
| 605 | + } | ||
| 603 | } | 606 | } |
| 604 | body.loop->compute_stage = this->compute_stage; | 607 | body.loop->compute_stage = this->compute_stage; |
| 605 | GE_CHK_STATUS_RET(body.loop->GenerateLoop(tiler, tpipe, current_axis, ss), "Generate loop for body failed"); | 608 | GE_CHK_STATUS_RET(body.loop->GenerateLoop(tiler, tpipe, current_axis, ss), "Generate loop for body failed"); |
| 606 | - for (auto call : target_calls) { | 609 | + if (it != cross_loop_map.end()) { |
| 607 | - GE_CHK_BOOL_RET_STATUS(call->SyncOutputs(tpipe, ss), af::FAILED, "Func SyncOutputs return false"); | 610 | + for (auto call : it->second) { |
| 611 | + GE_CHK_BOOL_RET_STATUS(call->SyncOutputs(tpipe, ss), af::FAILED, "Func SyncOutputs return false"); | ||
| 612 | + } | ||
| 608 | } | 613 | } |
| 609 | used_calls.clear(); | 614 | used_calls.clear(); |
| 610 | } else { | 615 | } else { |
| @@ -761,7 +766,7 @@ Status Loop::GenerateLoop(const Tiler &tiler, const TPipe &tpipe, std::vector<as | |||
| 761 | ss << "uint32_t " << reduce_dim_a << ";" << std::endl; | 766 | ss << "uint32_t " << reduce_dim_a << ";" << std::endl; |
| 762 | } | 767 | } |
| 763 | if (axis.type != Axis::Type::kAxisTypeBlockInner && this->is_graph_has_reduce_node) { | 768 | if (axis.type != Axis::Type::kAxisTypeBlockInner && this->is_graph_has_reduce_node) { |
| 764 | - ss << "bool control_dis_enable_cache_a = true;" << std::endl; | 769 | + ss << "control_dis_enable_cache_a = true;" << std::endl; |
| 765 | ss << "if ( " << axis.loop_size.Str() << " == 1) {" << std::endl; | 770 | ss << "if ( " << axis.loop_size.Str() << " == 1) {" << std::endl; |
| 766 | ss << "control_dis_enable_cache_a = false;" << std::endl; | 771 | ss << "control_dis_enable_cache_a = false;" << std::endl; |
| 767 | ss << "}" << std::endl; | 772 | ss << "}" << std::endl; |
| @@ -950,6 +955,9 @@ Status Loop::Generate(const Tiler &tiler, const TPipe &tpipe, std::string &resul | |||
| 950 | std::vector<ascir::AxisId> current_axis; | 955 | std::vector<ascir::AxisId> current_axis; |
| 951 | this->compute_stage = stage; | 956 | this->compute_stage = stage; |
| 952 | stringstream ss; | 957 | stringstream ss; |
| 958 | + if (this->is_graph_has_reduce_node) { | ||
| 959 | + ss << "bool control_dis_enable_cache_a = true;" << std::endl; | ||
| 960 | + } | ||
| 953 | GE_CHK_STATUS_RET(this->GenerateLoop(tiler, tpipe, current_axis, ss), "Generate loop failed"); | 961 | GE_CHK_STATUS_RET(this->GenerateLoop(tiler, tpipe, current_axis, ss), "Generate loop failed"); |
| 954 | result = ss.str(); | 962 | result = ss.str(); |
| 955 | return af::SUCCESS; | 963 | return af::SUCCESS; |
| @@ -177,7 +177,7 @@ struct Loop { | |||
| 177 | ComputeStage stage = ComputeStage::kDefault); | 177 | ComputeStage stage = ComputeStage::kDefault); |
| 178 | const Tensor *GetReduceOutputTensor(const TPipe &tpipe) const; | 178 | const Tensor *GetReduceOutputTensor(const TPipe &tpipe) const; |
| 179 | const Tensor *GetReduceInputTensor(const TPipe &tpipe) const; | 179 | const Tensor *GetReduceInputTensor(const TPipe &tpipe) const; |
| 180 | - void CollectTensorCrossLoop(std::map<ascir::AxisId, std::vector<ApiCall *>> &api_calls); | 180 | + void CollectTensorCrossLoop(std::map<ascir::AxisId, std::map<Loop *, std::vector<ApiCall *>>> &api_calls); |
| 181 | Status ActualSizeDefine(const Tiler &tiler, const TPipe &tpipe, std::string dtype_name, std::string &result); | 181 | Status ActualSizeDefine(const Tiler &tiler, const TPipe &tpipe, std::string dtype_name, std::string &result); |
| 182 | 182 | ||
| 183 | private: | 183 | private: |
| @@ -255,7 +255,7 @@ Status ReducePartitionCaseGenerator::GeneratorRCoreTask(ascir::HintGraph &optimi | |||
| 255 | std::map<size_t, std::vector<size_t>> map; | 255 | std::map<size_t, std::vector<size_t>> map; |
| 256 | size_t phase_2_graph_size = 0; | 256 | size_t phase_2_graph_size = 0; |
| 257 | for (size_t i = 0; i < task.grouped_graphs.size(); i++) { | 257 | for (size_t i = 0; i < task.grouped_graphs.size(); i++) { |
| 258 | - GE_ASSERT_TRUE(IsGroupGraphLegal(task.grouped_graphs[i])); | 258 | + GE_ASSERT_TRUE(IsOnlyHasOneOrLessReduce(task.grouped_graphs[i])); |
| 259 | if (!HasReduce(task.grouped_graphs[i])) { | 259 | if (!HasReduce(task.grouped_graphs[i])) { |
| 260 | ::ascir::ImplGraph graph((task.grouped_graphs[i].GetName() + "_r_multicore").c_str()); | 260 | ::ascir::ImplGraph graph((task.grouped_graphs[i].GetName() + "_r_multicore").c_str()); |
| 261 | graph.CopyFrom(task.grouped_graphs[i]); | 261 | graph.CopyFrom(task.grouped_graphs[i]); |
| @@ -304,10 +304,8 @@ Status ReducePartitionCaseGenerator::GeneratorTask(ascir::HintGraph &optimize_gr | |||
| 304 | const bool force_all_load = ShouldForceAllLoad(optimize_graph); | 304 | const bool force_all_load = ShouldForceAllLoad(optimize_graph); |
| 305 | GELOGI("Graph %s force AllLoad = %d, begin to generate reduce tasks.", optimize_graph.GetName().c_str(), | 305 | GELOGI("Graph %s force AllLoad = %d, begin to generate reduce tasks.", optimize_graph.GetName().c_str(), |
| 306 | static_cast<int32_t>(force_all_load)); | 306 | static_cast<int32_t>(force_all_load)); |
| 307 | - if (!force_all_load || options.graph_type != GraphType::kFusedAscBackend) { | 307 | + GE_CHK_STATUS_RET(GeneratorGeneralTask(optimize_graph, tasks)); |
| 308 | - GE_CHK_STATUS_RET(GeneratorGeneralTask(optimize_graph, tasks)); | 308 | + GELOGI("After GeneralTask, graph %s has %zu task(s).", optimize_graph.GetName().c_str(), tasks.size()); |
| 309 | - GELOGI("After GeneralTask, graph %s has %zu task(s).", optimize_graph.GetName().c_str(), tasks.size()); | ||
| 310 | - } | ||
| 311 | if (!force_all_load) { | 309 | if (!force_all_load) { |
| 312 | GE_CHK_STATUS_RET(GeneratorRCoreTask(optimize_graph, tasks)); | 310 | GE_CHK_STATUS_RET(GeneratorRCoreTask(optimize_graph, tasks)); |
| 313 | GELOGI("After RCoreTask, graph %s has %zu task(s).", optimize_graph.GetName().c_str(), tasks.size()); | 311 | GELOGI("After RCoreTask, graph %s has %zu task(s).", optimize_graph.GetName().c_str(), tasks.size()); |
| @@ -324,7 +322,7 @@ Status ReducePartitionCaseGenerator::Generate([[maybe_unused]] ascir::HintGraph | |||
| 324 | } | 322 | } |
| 325 | 323 | ||
| 326 | bool ReducePartitionCaseGenerator::ShouldForceAllLoad(ascir::HintGraph &graph) { | 324 | bool ReducePartitionCaseGenerator::ShouldForceAllLoad(ascir::HintGraph &graph) { |
| 327 | - if (!IsGroupGraphLegal(graph)) { | 325 | + if (!IsOnlyHasOneOrLessReduce(graph)) { |
| 328 | return true; | 326 | return true; |
| 329 | } | 327 | } |
| 330 | 328 | ||
| @@ -400,7 +398,7 @@ Status ReducePartitionCaseGenerator::GenerateAllLoadCase(ascir::HintGraph &graph | |||
| 400 | } | 398 | } |
| 401 | 399 | ||
| 402 | Status ReducePartitionCaseGenerator::ReducePartitionMultipleCitations(ascir::ImplGraph &impl_graph) { | 400 | Status ReducePartitionCaseGenerator::ReducePartitionMultipleCitations(ascir::ImplGraph &impl_graph) { |
| 403 | - if (IsGroupGraphLegal(impl_graph)) { | 401 | + if (IsOnlyHasOneOrLessReduce(impl_graph)) { |
| 404 | return ge::GRAPH_SUCCESS; | 402 | return ge::GRAPH_SUCCESS; |
| 405 | } | 403 | } |
| 406 | std::vector<af::AscNodePtr> multi_output_nodes; | 404 | std::vector<af::AscNodePtr> multi_output_nodes; |
| @@ -510,20 +508,25 @@ Status ReducePartitionCaseGenerator::PartitionLoadNode(af::AscNodePtr &src_load_ | |||
| 510 | auto load_node = impl_graph.AddNode(load); | 508 | auto load_node = impl_graph.AddNode(load); |
| 511 | DoCopyAscNodeTensorAttr(load_input_asc_node, new_load_input_node); | 509 | DoCopyAscNodeTensorAttr(load_input_asc_node, new_load_input_node); |
| 512 | DoCopyAscNodeTensorAttr(src_load_node, load_node); | 510 | DoCopyAscNodeTensorAttr(src_load_node, load_node); |
| 511 | + // dst_node 的多个输入可能来自同一个 src_load_node(如 Mul 的两个输入都是同一个 Load), | ||
| 512 | + // 需要遍历所有 peer 边逐一断开并替换,不能找到第一条就 return。 | ||
| 513 | + // new_load_input -> load_node 的边只需建一次,后续匹配的 peer 边共用这条链路。 | ||
| 514 | + bool found = false; | ||
| 513 | for (const auto &out_anchor : src_load_node->GetAllOutDataAnchors()) { | 515 | for (const auto &out_anchor : src_load_node->GetAllOutDataAnchors()) { |
| 514 | GE_CHECK_NOTNULL(out_anchor, "Out data anchor is null, node:%s.", src_load_node->GetNamePtr()); | 516 | GE_CHECK_NOTNULL(out_anchor, "Out data anchor is null, node:%s.", src_load_node->GetNamePtr()); |
| 515 | for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { | 517 | for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { |
| 516 | GE_CHECK_NOTNULL(peer_in_anchor); | 518 | GE_CHECK_NOTNULL(peer_in_anchor); |
| 517 | GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNodeBarePtr(), "Peer in node:%s is null", src_load_node->GetNamePtr()); | 519 | GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNodeBarePtr(), "Peer in node:%s is null", src_load_node->GetNamePtr()); |
| 518 | if (peer_in_anchor->GetOwnerNodeBarePtr() == dst_node.get()) { | 520 | if (peer_in_anchor->GetOwnerNodeBarePtr() == dst_node.get()) { |
| 519 | - // remove load->dst | 521 | + if (!found) { |
| 522 | + found = true; | ||
| 523 | + GE_CHK_STATUS_RET( | ||
| 524 | + af::GraphUtils::AddEdge(new_load_input_node->GetOutAnchor(0UL), load_node->GetInAnchor(0UL))); | ||
| 525 | + } | ||
| 520 | GE_CHK_STATUS_RET(af::GraphUtils::RemoveEdge(src_load_node->GetOutAnchor(out_anchor->GetIdx()), | 526 | GE_CHK_STATUS_RET(af::GraphUtils::RemoveEdge(src_load_node->GetOutAnchor(out_anchor->GetIdx()), |
| 521 | dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); | 527 | dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); |
| 522 | - // add new_load_input->new_load->dst | ||
| 523 | - GE_CHK_STATUS_RET(af::GraphUtils::AddEdge(new_load_input_node->GetOutAnchor(0UL), load_node->GetInAnchor(0UL))); | ||
| 524 | GE_CHK_STATUS_RET( | 528 | GE_CHK_STATUS_RET( |
| 525 | af::GraphUtils::AddEdge(load_node->GetOutAnchor(0UL), dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); | 529 | af::GraphUtils::AddEdge(load_node->GetOutAnchor(0UL), dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); |
| 526 | - return ge::GRAPH_SUCCESS; | ||
| 527 | } | 530 | } |
| 528 | } | 531 | } |
| 529 | } | 532 | } |
| @@ -541,19 +544,17 @@ Status ReducePartitionCaseGenerator::PartitionScalarNode(af::AscNodePtr &src_nod | |||
| 541 | scalar_node = impl_graph.AddNode(scalar); | 544 | scalar_node = impl_graph.AddNode(scalar); |
| 542 | } | 545 | } |
| 543 | DoCopyAscNodeTensorAttr(src_node, scalar_node); | 546 | DoCopyAscNodeTensorAttr(src_node, scalar_node); |
| 547 | + // dst_node 的多个输入可能来自同一个 src_node,需要遍历所有 peer 边逐一断开并替换,不能找到第一条就 return。 | ||
| 544 | for (const auto &out_anchor : src_node->GetAllOutDataAnchors()) { | 548 | for (const auto &out_anchor : src_node->GetAllOutDataAnchors()) { |
| 545 | GE_CHECK_NOTNULL(out_anchor, "Out data anchor is null, node:%s.", src_node->GetNamePtr()); | 549 | GE_CHECK_NOTNULL(out_anchor, "Out data anchor is null, node:%s.", src_node->GetNamePtr()); |
| 546 | for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { | 550 | for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { |
| 547 | GE_CHECK_NOTNULL(peer_in_anchor); | 551 | GE_CHECK_NOTNULL(peer_in_anchor); |
| 548 | GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNodeBarePtr(), "Peer in node:%s is null", src_node->GetNamePtr()); | 552 | GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNodeBarePtr(), "Peer in node:%s is null", src_node->GetNamePtr()); |
| 549 | if (peer_in_anchor->GetOwnerNodeBarePtr() == dst_node.get()) { | 553 | if (peer_in_anchor->GetOwnerNodeBarePtr() == dst_node.get()) { |
| 550 | - // remove src->dst | ||
| 551 | GE_CHK_STATUS_RET(af::GraphUtils::RemoveEdge(src_node->GetOutAnchor(out_anchor->GetIdx()), | 554 | GE_CHK_STATUS_RET(af::GraphUtils::RemoveEdge(src_node->GetOutAnchor(out_anchor->GetIdx()), |
| 552 | dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); | 555 | dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); |
| 553 | - // add new_scalar->dst | ||
| 554 | GE_CHK_STATUS_RET( | 556 | GE_CHK_STATUS_RET( |
| 555 | af::GraphUtils::AddEdge(scalar_node->GetOutAnchor(0UL), dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); | 557 | af::GraphUtils::AddEdge(scalar_node->GetOutAnchor(0UL), dst_node->GetInAnchor(peer_in_anchor->GetIdx()))); |
| 556 | - return ge::GRAPH_SUCCESS; | ||
| 557 | } | 558 | } |
| 558 | } | 559 | } |
| 559 | } | 560 | } |
| @@ -760,7 +761,7 @@ bool ReducePartitionCaseGenerator::CanFullLoadReduceFuse(const ascir::ImplGraph | |||
| 760 | return true; | 761 | return true; |
| 761 | } | 762 | } |
| 762 | 763 | ||
| 763 | -bool ReducePartitionCaseGenerator::IsGroupGraphLegal(const ascir::ImplGraph &impl_graph) { | 764 | +bool ReducePartitionCaseGenerator::IsOnlyHasOneOrLessReduce(const ascir::ImplGraph &impl_graph) { |
| 764 | int reduce_count = 0; | 765 | int reduce_count = 0; |
| 765 | for (const auto &node : impl_graph.GetAllNodes()) { | 766 | for (const auto &node : impl_graph.GetAllNodes()) { |
| 766 | if (ScheduleUtils::IsReduce(node)) { | 767 | if (ScheduleUtils::IsReduce(node)) { |
| @@ -52,7 +52,7 @@ class ReducePartitionCaseGenerator : public FusionCaseGenerator { | |||
| 52 | static Status PartitionScalarNode(af::AscNodePtr &src_node, af::AscNodePtr &dst_node, ascir::ImplGraph &impl_graph); | 52 | static Status PartitionScalarNode(af::AscNodePtr &src_node, af::AscNodePtr &dst_node, ascir::ImplGraph &impl_graph); |
| 53 | static bool HasReduce(const ascir::ImplGraph &impl_graph); | 53 | static bool HasReduce(const ascir::ImplGraph &impl_graph); |
| 54 | static bool HasArgMaxReduce(const ScheduleTask &task); | 54 | static bool HasArgMaxReduce(const ScheduleTask &task); |
| 55 | - static bool IsGroupGraphLegal(const ascir::ImplGraph &impl_graph); | 55 | + static bool IsOnlyHasOneOrLessReduce(const ascir::ImplGraph &impl_graph); |
| 56 | static bool CanFullLoadReduceFuse(const ascir::ImplGraph &impl_graph); | 56 | static bool CanFullLoadReduceFuse(const ascir::ImplGraph &impl_graph); |
| 57 | Status ReducePartitionMultipleCitations(ascir::ImplGraph &impl_graph); | 57 | Status ReducePartitionMultipleCitations(ascir::ImplGraph &impl_graph); |
| 58 | bool FindOutputReduce(const af::AscNodePtr &node, af::AscNodePtr &reduce_node); | 58 | bool FindOutputReduce(const af::AscNodePtr &node, af::AscNodePtr &reduce_node); |
| @@ -97,6 +97,7 @@ Status ScheduleGroupGraphPartitioner::PartitionByConnectivity(const ::ascir::Imp | |||
| 97 | for (auto &sub_optimize_graph : sub_optimize_graphs) { | 97 | for (auto &sub_optimize_graph : sub_optimize_graphs) { |
| 98 | GE_CHK_STATUS_RET(ScheduleUtils::RemoveUnusedAxes(sub_optimize_graph), "Failed to remove unused axes"); | 98 | GE_CHK_STATUS_RET(ScheduleUtils::RemoveUnusedAxes(sub_optimize_graph), "Failed to remove unused axes"); |
| 99 | } | 99 | } |
| 100 | + GE_CHK_STATUS_RET(SortSubGraphsByDependency(sub_optimize_graphs), "Failed to sort subgraphs by dependency"); | ||
| 100 | } | 101 | } |
| 101 | if (visited.size() != num_nodes) { | 102 | if (visited.size() != num_nodes) { |
| 102 | for (const auto &node : optimize_graph.GetAllNodes()) { | 103 | for (const auto &node : optimize_graph.GetAllNodes()) { |
| @@ -179,6 +180,78 @@ bool ScheduleGroupGraphPartitioner::CompareByNodeId(const AscNodePtr &lhs, const | |||
| 179 | return lhs->GetOpDesc()->GetId() < rhs->GetOpDesc()->GetId(); | 180 | return lhs->GetOpDesc()->GetId() < rhs->GetOpDesc()->GetId(); |
| 180 | } | 181 | } |
| 181 | 182 | ||
| 183 | +bool ScheduleGroupGraphPartitioner::HasDataDependency(const ::ascir::ImplGraph &producer, | ||
| 184 | + const ::ascir::ImplGraph &consumer) { | ||
| 185 | + std::set<std::string> producer_output_names; | ||
| 186 | + for (const auto &node : producer.GetAllNodes()) { | ||
| 187 | + if (node->GetOutDataNodes().empty()) { | ||
| 188 | + producer_output_names.insert(node->GetName()); | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | + if (producer_output_names.empty()) { | ||
| 192 | + return false; | ||
| 193 | + } | ||
| 194 | + for (const auto &node : consumer.GetAllNodes()) { | ||
| 195 | + for (const auto &in_node : node->GetInDataNodes()) { | ||
| 196 | + if (producer_output_names.find(in_node->GetName()) != producer_output_names.end()) { | ||
| 197 | + return true; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + return false; | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +Status ScheduleGroupGraphPartitioner::SortSubGraphsByDependency(std::vector<::ascir::ImplGraph> &sub_optimize_graphs) { | ||
| 205 | + const size_t n = sub_optimize_graphs.size(); | ||
| 206 | + if (n <= 1U) { | ||
| 207 | + return af::SUCCESS; | ||
| 208 | + } | ||
| 209 | + std::vector<std::vector<bool>> dep_matrix(n, std::vector<bool>(n, false)); | ||
| 210 | + std::vector<size_t> in_degree(n, 0U); | ||
| 211 | + for (size_t i = 0U; i < n; ++i) { | ||
| 212 | + for (size_t j = 0U; j < n; ++j) { | ||
| 213 | + if (i != j) { | ||
| 214 | + dep_matrix[i][j] = HasDataDependency(sub_optimize_graphs[i], sub_optimize_graphs[j]); | ||
| 215 | + if (dep_matrix[i][j]) { | ||
| 216 | + ++in_degree[j]; | ||
| 217 | + } | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + } | ||
| 221 | + std::vector<size_t> sorted; | ||
| 222 | + sorted.reserve(n); | ||
| 223 | + std::queue<size_t> zero_in_degree_queue; | ||
| 224 | + for (size_t i = 0U; i < n; ++i) { | ||
| 225 | + if (in_degree[i] == 0U) { | ||
| 226 | + zero_in_degree_queue.push(i); | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + while (!zero_in_degree_queue.empty()) { | ||
| 230 | + size_t idx = zero_in_degree_queue.front(); | ||
| 231 | + zero_in_degree_queue.pop(); | ||
| 232 | + sorted.emplace_back(idx); | ||
| 233 | + for (size_t j = 0U; j < n; ++j) { | ||
| 234 | + if (dep_matrix[idx][j]) { | ||
| 235 | + --in_degree[j]; | ||
| 236 | + if (in_degree[j] == 0U) { | ||
| 237 | + zero_in_degree_queue.push(j); | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + if (sorted.size() != n) { | ||
| 243 | + GELOGE(af::FAILED, "Cycle detected in subgraph dependency, sorted[%zu] != total[%zu]", sorted.size(), n); | ||
| 244 | + return af::FAILED; | ||
| 245 | + } | ||
| 246 | + std::vector<::ascir::ImplGraph> reordered; | ||
| 247 | + reordered.reserve(n); | ||
| 248 | + for (const auto idx : sorted) { | ||
| 249 | + reordered.emplace_back(std::move(sub_optimize_graphs[idx])); | ||
| 250 | + } | ||
| 251 | + sub_optimize_graphs = std::move(reordered); | ||
| 252 | + return af::SUCCESS; | ||
| 253 | +} | ||
| 254 | + | ||
| 182 | Status ScheduleGroupGraphPartitioner::RecordAxisSizes(const std::vector<af::Expression> &repeats, | 255 | Status ScheduleGroupGraphPartitioner::RecordAxisSizes(const std::vector<af::Expression> &repeats, |
| 183 | const std::vector<int64_t> &axis_ids, | 256 | const std::vector<int64_t> &axis_ids, |
| 184 | std::map<af::AxisId, af::Expression> &axis_id_to_size) { | 257 | std::map<af::AxisId, af::Expression> &axis_id_to_size) { |
| @@ -46,6 +46,8 @@ class ScheduleGroupGraphPartitioner { | |||
| 46 | static bool CompareByNodeId(const af::AscNodePtr &lhs, const af::AscNodePtr &rhs); | 46 | static bool CompareByNodeId(const af::AscNodePtr &lhs, const af::AscNodePtr &rhs); |
| 47 | static Status RecordAxisSizes(const std::vector<af::Expression> &repeats, const std::vector<int64_t> &axis_ids, | 47 | static Status RecordAxisSizes(const std::vector<af::Expression> &repeats, const std::vector<int64_t> &axis_ids, |
| 48 | std::map<af::AxisId, af::Expression> &axis_id_to_size); | 48 | std::map<af::AxisId, af::Expression> &axis_id_to_size); |
| 49 | + static Status SortSubGraphsByDependency(std::vector<::ascir::ImplGraph> &sub_optimize_graphs); | ||
| 50 | + static bool HasDataDependency(const ::ascir::ImplGraph &producer, const ::ascir::ImplGraph &consumer); | ||
| 49 | }; | 51 | }; |
| 50 | } // namespace optimize | 52 | } // namespace optimize |
| 51 | 53 | ||