1 /**
2 * Copyright 2019-2023 Huawei Technologies Co., Ltd
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 "ir/func_graph_base.h"
17
18 #include <list>
19 #include <algorithm>
20 #include "ir/func_graph.h"
21 #include "ir/meta_func_graph.h"
22
23 namespace mindspore {
~FuncGraphLoopBreaker()24 FuncGraphLoopBreaker::~FuncGraphLoopBreaker() {
25 std::lock_guard<std::mutex> lock_set(func_mutex_);
26 for (auto fg : func_set_) {
27 MS_EXCEPTION_IF_NULL(fg);
28 fg->reg_flg_ = false;
29 }
30 }
31
Inst()32 FuncGraphLoopBreaker &FuncGraphLoopBreaker::Inst() {
33 static FuncGraphLoopBreaker mgr;
34 return mgr;
35 }
36
GetChecker(const std::string & checker_name)37 MS_CORE_API const FuncGraphChecker &FuncGraphBase::GetChecker(const std::string &checker_name) {
38 auto it = checkers_.find(checker_name);
39 if (it == checkers_.cend()) {
40 static const auto empty_checker = FuncGraphChecker();
41 return empty_checker;
42 }
43 return *(it->second);
44 }
45
AddChecker(const std::string & checker_name,const std::shared_ptr<FuncGraphChecker> & new_checker)46 MS_CORE_API void FuncGraphBase::AddChecker(const std::string &checker_name,
47 const std::shared_ptr<FuncGraphChecker> &new_checker) {
48 (void)checkers_.emplace(checker_name, new_checker);
49 }
50
BreakLoop()51 void FuncGraphLoopBreaker::BreakLoop() {
52 MS_LOG(INFO) << "Size of not recycled graph before break loop is:" << func_set_.size();
53 std::list<FuncGraphBasePtr> func_list;
54
55 // Generate shared_ptr for every graph, to avoid func_set_ changes while BreakLoop
56 (void)std::for_each(func_set_.begin(), func_set_.end(), [&func_list](FuncGraphBase *fun) {
57 if (fun != nullptr && !fun->subclass_destruct_flag_) {
58 (void)func_list.emplace_back(fun->shared_from_base<FuncGraphBase>());
59 }
60 });
61 for (auto &item : func_list) {
62 if (item == nullptr) {
63 continue;
64 }
65 item->DoBreakLoop();
66 }
67 func_list.clear();
68
69 int func_graph_cnt = 0;
70 for (auto item : func_set_) {
71 if (item->isa<FuncGraph>()) {
72 MS_LOG(INFO) << "Unfree graph info:" << item->ToString();
73 func_graph_cnt++;
74 }
75 }
76 if (func_graph_cnt > 0) {
77 MS_LOG(INFO) << "Size of not recycled graph after break loop should be 0, but got: " << func_graph_cnt << "\n"
78 << "Please check the usage of clear_compile_cache or contact to the maintenance engineers.";
79 }
80 }
81
Dump() const82 void FuncGraphLoopBreaker::Dump() const {
83 MS_LOG(INFO) << "Total func graphs: " << func_set_.size();
84 for (const auto &fun : func_set_) {
85 if (fun != nullptr && !fun->subclass_destruct_flag_) {
86 const auto &f = fun->shared_from_base<FuncGraphBase>();
87 auto use_count = f.use_count();
88 const auto &fg = dyn_cast<FuncGraph>(f);
89 MS_LOG(INFO) << "FuncGraph: " << f << "/" << f->ToString() << ", use_count: " << use_count
90 << (fg != nullptr ? (std::string(", attached_mng_cnt: ") + std::to_string(fg->attached_mng_cnt()))
91 : "")
92 << ", type: " << f->type_name();
93 }
94 }
95 }
96
CleanMetaFuncGraphs()97 void FuncGraphLoopBreaker::CleanMetaFuncGraphs() {
98 std::list<FuncGraphBasePtr> func_list;
99 // Generate shared_ptr for every graph, to avoid func_set_ changes while BreakLoop
100 (void)std::for_each(func_set_.begin(), func_set_.end(), [&func_list](FuncGraphBase *fun) {
101 if (fun != nullptr && !fun->subclass_destruct_flag_) {
102 (void)func_list.emplace_back(fun->shared_from_base<FuncGraphBase>());
103 }
104 });
105 for (auto item : func_list) {
106 if (item == nullptr) {
107 continue;
108 }
109 if (item->isa<MetaFuncGraph>()) {
110 item->DoBreakLoop();
111 }
112 }
113 }
114
115 // If phase is empty, clean all collected func graphs.
CleanUnusedFuncGraphs(const std::string & phase)116 void FuncGraphLoopBreaker::CleanUnusedFuncGraphs(const std::string &phase) {
117 std::list<FuncGraphBasePtr> func_list;
118 // Generate shared_ptr for every graph, to avoid func_set_ changes while BreakLoop
119 (void)std::for_each(func_set_.begin(), func_set_.end(), [&func_list](FuncGraphBase *fun) {
120 if (fun != nullptr && !fun->subclass_destruct_flag_) {
121 (void)func_list.emplace_back(fun->shared_from_base<FuncGraphBase>());
122 }
123 });
124 for (auto item : func_list) {
125 if (item == nullptr) {
126 continue;
127 }
128 const auto &fg = dyn_cast<FuncGraph>(item);
129 if (fg == nullptr || !fg->IsSameTypeId(FuncGraph::kTypeId)) {
130 continue;
131 }
132 if (!phase.empty() && fg->phase() != phase) {
133 continue;
134 }
135 MS_LOG(INFO) << "Drop " << fg << "/" << fg->ToString() << ", use_count: " << fg.use_count()
136 << ", type: " << fg->type_name();
137 fg->ResetReturnOwner();
138 fg->ResetOwnNodes();
139 fg->set_dropped(true);
140 }
141 }
142
ClearCellGraphs(const std::string & phase)143 void FuncGraphLoopBreaker::ClearCellGraphs(const std::string &phase) {
144 std::list<FuncGraphBasePtr> func_list;
145 // Generate shared_ptr for every graph, to avoid func_set_ changes while BreakLoop
146 (void)std::for_each(func_set_.begin(), func_set_.end(), [&func_list](FuncGraphBase *fun) {
147 if (fun != nullptr && !fun->subclass_destruct_flag_) {
148 (void)func_list.emplace_back(fun->shared_from_base<FuncGraphBase>());
149 }
150 });
151 for (auto item : func_list) {
152 if (item != nullptr && item->isa<FuncGraph>()) {
153 auto func_graph = item->cast<FuncGraphPtr>();
154 if (func_graph != nullptr && func_graph->phase() == phase) {
155 func_graph->DoBreakLoop();
156 }
157 }
158 }
159 }
160 } // namespace mindspore
161