• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2022 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 "tools/graph_kernel/converter/graph_kernel_pass_manager_lite.h"
17 
18 #include <vector>
19 #include <string>
20 #include <memory>
21 #include <algorithm>
22 #include <iomanip>
23 #include <optional>
24 #include "ir/graph_utils.h"
25 #include "src/common/file_utils.h"
26 #include "utils/file_utils.h"
27 #include "src/common/utils.h"
28 #include "utils/anf_utils.h"
29 #include "tools/graph_kernel/common/utils.h"
30 
31 namespace mindspore::graphkernel {
32 namespace dumpir {
33 struct SubGraphIRInfo {
34   int32_t local_var;
35   std::ostringstream dumpbuf;
36   OrderedMap<AnfNodePtr, int32_t> local_var_map;
37 };
38 
DumpGlobalInfoEntry(const FuncGraphPtr & graph,std::ostringstream & dumpbuf)39 void DumpGlobalInfoEntry(const FuncGraphPtr &graph, std::ostringstream &dumpbuf) {
40   if (graph == nullptr) {
41     return;
42   }
43   dumpbuf << "#IR entry      : @" << graph->ToString() << std::endl;
44   dumpbuf << "#attrs         :" << std::endl;
45   for (const auto &attr : graph->attrs()) {
46     dumpbuf << attr.first << " : ";
47     if (attr.second->isa<BoolImm>()) {
48       dumpbuf << (GetValue<bool>(attr.second));
49     } else if (attr.second->isa<StringImm>()) {
50       dumpbuf << (GetValue<std::string>(attr.second));
51     }
52     dumpbuf << std::endl;
53   }
54 }
55 
PrintNodeOutputType(std::ostringstream & dumpbuf,const AnfNodePtr & nd)56 void PrintNodeOutputType(std::ostringstream &dumpbuf, const AnfNodePtr &nd) {
57   if (nd == nullptr) {
58     return;
59   }
60   ValuePtr tensor_value = nullptr;
61   auto abstract = nd->abstract();
62   if (abstract != nullptr && abstract->isa<abstract::AbstractTensor>()) {
63     tensor_value = abstract->BuildValue();
64   }
65   abstract::ShapePtr shape = dyn_cast<abstract::Shape>(nd->Shape());
66   TypePtr type = dyn_cast<Type>(nd->Type());
67   if ((shape != nullptr) && (type != nullptr)) {
68     dumpbuf << "<" << type << ", " << shape->ToString();
69     if (tensor_value != nullptr && tensor_value != kValueAny) {
70       dumpbuf << ", value=...";
71     }
72     dumpbuf << ">";
73   } else if (type != nullptr) {
74     dumpbuf << "<" << type;
75     if (tensor_value != nullptr && tensor_value != kValueAny) {
76       dumpbuf << ", value=...";
77     }
78     dumpbuf << ">";
79   } else {
80     dumpbuf << "<null>";
81   }
82 }
83 
DumpParams(const FuncGraphPtr & graph,std::ostringstream & dumpbuf,OrderedMap<AnfNodePtr,int32_t> * para_map)84 int32_t DumpParams(const FuncGraphPtr &graph, std::ostringstream &dumpbuf, OrderedMap<AnfNodePtr, int32_t> *para_map) {
85   if (graph == nullptr) {
86     MS_LOG(INFO) << "Param graph is nullptr.";
87     return 0;
88   }
89   std::vector<AnfNodePtr> parameters = graph->parameters();
90   dumpbuf << "#Total params  : " << parameters.size() << std::endl;
91   dumpbuf << std::endl;
92 
93   // dump parameters
94   int32_t para = 1;
95   for (const auto &p : parameters) {
96     if (p == nullptr) {
97       continue;
98     }
99     auto parameter_ptr = p->cast<ParameterPtr>();
100     if (parameter_ptr == nullptr) {
101       MS_LOG(EXCEPTION) << "p cannot cast to ParameterPtr";
102     }
103     dumpbuf << "%para" << para << "_" << parameter_ptr->name() << " : ";
104     // print parameters' type and shape
105     PrintNodeOutputType(dumpbuf, p);
106     dumpbuf << std::endl;
107 
108     if (para_map != nullptr) {
109       (*para_map)[p] = para++;
110     }
111     MS_LOG(DEBUG) << "Record param: " << p->ToString() << " graph belong : " << p->func_graph()->ToString();
112   }
113   return para;
114 }
115 
DumpOperator(const AnfNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)116 void DumpOperator(const AnfNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
117   if (op == nullptr || gsub == nullptr) {
118     return;
119   }
120 
121   if (IsValueNode<FuncGraph>(op)) {
122     FuncGraphPtr fg = GetValueNode<FuncGraphPtr>(op);
123     if (fg != nullptr) {
124       gsub->dumpbuf << "call @" << fg->ToString();
125     }
126   } else if (op->isa<CNode>()) {
127     if (gsub->local_var_map.find(op) != gsub->local_var_map.end()) {
128       gsub->dumpbuf << "%" << gsub->local_var_map[op];
129     } else {
130       auto node = op->cast<CNodePtr>();
131       auto fg = node->func_graph();
132       gsub->dumpbuf << "$(" << fg->ToString() << ":" << node->ToString() << ")";
133     }
134   } else if (op->isa<ValueNode>()) {
135     gsub->dumpbuf << GetValueNode(op)->ToString();
136   } else {
137     gsub->dumpbuf << op->ToString();
138   }
139 }
140 
DumpOperands(const AnfNodePtr & nd,OrderedMap<AnfNodePtr,int32_t> * para_map,const std::shared_ptr<SubGraphIRInfo> & gsub)141 void DumpOperands(const AnfNodePtr &nd, OrderedMap<AnfNodePtr, int32_t> *para_map,
142                   const std::shared_ptr<SubGraphIRInfo> &gsub) {
143   if (nd == nullptr || para_map == nullptr || gsub == nullptr) {
144     return;
145   }
146 
147   gsub->dumpbuf << "(";
148   const auto &inputs = GetInputs(nd);
149   size_t len = inputs.size();
150   if (len > 1) {
151     // skip inputs[0] which is Primitive valuenode
152     for (size_t i = 1; i < len; ++i) {
153       AnfNodePtr in = inputs[i];
154       MS_EXCEPTION_IF_NULL(in);
155       if (i != 1) {
156         gsub->dumpbuf << ", ";
157       }
158       if (in->isa<Parameter>()) {
159         if (!(*para_map)[in]) {
160           gsub->dumpbuf << "%para_" << in->ToString();
161         } else {
162           gsub->dumpbuf << "%para" << (*para_map)[in] << "_" << in->ToString();
163         }
164       } else if (in->isa<CNode>()) {
165         if (gsub->local_var_map.find(in) != gsub->local_var_map.end()) {
166           gsub->dumpbuf << "%" << gsub->local_var_map[in];
167         } else {
168           auto node = in->cast<CNodePtr>();
169           auto fg = node->func_graph();
170           gsub->dumpbuf << "$(" << fg->ToString() << ":" << node->ToString() << ")";
171         }
172       } else if (in->isa<ValueNode>() && !IsValueNode<FuncGraph>(in)) {
173         // non Primitive valuenode
174         gsub->dumpbuf << GetValueNode(in)->ToString();
175       } else if (IsValueNode<FuncGraph>(in)) {
176         FuncGraphPtr fg = GetValueNode<FuncGraphPtr>(in);
177         gsub->dumpbuf << "@" << fg->ToString();
178       } else {
179         gsub->dumpbuf << in->ToString();
180       }
181     }
182   }
183   gsub->dumpbuf << ")";
184 }
185 
DumpAttrs(const mindspore::HashMap<std::string,ValuePtr> & attrs,const std::shared_ptr<SubGraphIRInfo> & gsub,bool check_strategy=false)186 void DumpAttrs(const mindspore::HashMap<std::string, ValuePtr> &attrs, const std::shared_ptr<SubGraphIRInfo> &gsub,
187                bool check_strategy = false) {
188   int i = 0;
189   for (const auto &attr : attrs) {
190     if (i++ != 0) {
191       gsub->dumpbuf << ", ";
192     }
193     gsub->dumpbuf << attr.first << ": ";
194     if (attr.second == nullptr) {
195       gsub->dumpbuf << "null";
196     } else {
197       gsub->dumpbuf << attr.second->ToString();
198     }
199   }
200 }
201 
DumpOperateAttrs(const AnfNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)202 void DumpOperateAttrs(const AnfNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
203   if (op == nullptr || gsub == nullptr) {
204     return;
205   }
206 
207   if (IsValueNode<Primitive>(op)) {
208     auto primitive = GetValueNode<PrimitivePtr>(op);
209     if (!primitive->instance_name().empty()) {
210       gsub->dumpbuf << " {";
211       gsub->dumpbuf << "instance name"
212                     << ": ";
213       gsub->dumpbuf << primitive->instance_name();
214       gsub->dumpbuf << "}";
215     }
216     auto attrs = primitive->attrs();
217     if (!attrs.empty()) {
218       gsub->dumpbuf << " primitive_attrs: {";
219       DumpAttrs(attrs, gsub, true);
220       gsub->dumpbuf << "}";
221     }
222   }
223 }
224 
DumpCNodeAttrs(const CNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)225 void DumpCNodeAttrs(const CNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
226   if (op == nullptr || gsub == nullptr) {
227     return;
228   }
229   auto &attrs = op->attrs();
230   if (attrs.empty()) {
231     return;
232   }
233 
234   gsub->dumpbuf << " cnode_attrs: {";
235   DumpAttrs(attrs, gsub);
236   gsub->dumpbuf << "}";
237 }
238 
DumpCNodePrimalAttrs(const CNodePtr & op,const std::shared_ptr<SubGraphIRInfo> & gsub)239 void DumpCNodePrimalAttrs(const CNodePtr &op, const std::shared_ptr<SubGraphIRInfo> &gsub) {
240   if (op == nullptr || gsub == nullptr) {
241     return;
242   }
243   if (op->primal_attrs().empty()) {
244     gsub->dumpbuf << std::endl;
245     return;
246   }
247   auto primal_attrs = op->primal_attrs();
248   gsub->dumpbuf << " cnode_primal_attrs: {";
249   DumpAttrs(primal_attrs, gsub);
250   gsub->dumpbuf << "}";
251   gsub->dumpbuf << std::endl;
252 }
253 
PrintNodeInputType(std::ostringstream & dumpbuf,const AnfNodePtr & nd)254 void PrintNodeInputType(std::ostringstream &dumpbuf, const AnfNodePtr &nd) {
255   if (nd == nullptr) {
256     return;
257   }
258   const auto &inputs = GetInputs(nd);
259   size_t len = inputs.size();
260   if (len > 1) {
261     // skip inputs[0] which is Primitive value node
262     for (size_t i = 1; i < len; ++i) {
263       AnfNodePtr in = inputs[i];
264       if (i != 1) {
265         dumpbuf << ", ";
266       }
267       PrintNodeOutputType(dumpbuf, in);
268     }
269   }
270 }
271 
DumpShape(const AnfNodePtr & nd,const FuncGraphPtr & sub_graph,const std::shared_ptr<SubGraphIRInfo> & gsub)272 void DumpShape(const AnfNodePtr &nd, const FuncGraphPtr &sub_graph, const std::shared_ptr<SubGraphIRInfo> &gsub) {
273   if (nd == nullptr || sub_graph == nullptr || gsub == nullptr) {
274     return;
275   }
276 
277   if (nd != sub_graph->get_return()) {
278     gsub->dumpbuf << "      : (";
279     PrintNodeInputType(gsub->dumpbuf, nd);
280     gsub->dumpbuf << ") -> (";
281     PrintNodeOutputType(gsub->dumpbuf, nd);
282     gsub->dumpbuf << ")";
283   } else {
284     gsub->dumpbuf << "      : (";
285     PrintNodeInputType(gsub->dumpbuf, nd);
286     gsub->dumpbuf << ")";
287   }
288 
289   gsub->dumpbuf << std::endl;
290 }
291 
PrintKernelFormatAndType(const std::string & fmt,const TypeId & type,const std::vector<int64_t> & shape)292 std::string PrintKernelFormatAndType(const std::string &fmt, const TypeId &type, const std::vector<int64_t> &shape) {
293   std::ostringstream buffer;
294   buffer << "<" << TypeIdLabel(type);
295   if (!fmt.empty()) {
296     buffer << "x" << fmt << shape;
297   }
298   buffer << ">";
299   return buffer.str();
300 }
301 
PrintOutputTypeShapeFormat(const std::shared_ptr<AnfNode> & node)302 std::string PrintOutputTypeShapeFormat(const std::shared_ptr<AnfNode> &node) {
303   if (node == nullptr) {
304     return "";
305   }
306   std::ostringstream buffer;
307   auto kernel_build_info = GetKernelInfo(node);
308   if (kernel_build_info == nullptr) {
309     return "";
310   }
311   size_t output_num = kernel_build_info->GetOutputNum();
312   buffer << "OutputFormats:";
313   for (size_t i = 0; i < output_num; ++i) {
314     if (i != 0) {
315       buffer << ", ";
316     }
317     auto format = GetOutputFormatFromAnfNode(node, i);
318     if (!format.empty()) {
319       buffer << format;
320     }
321   }
322   return buffer.str();
323 }
324 
DumpKernelInfo(const CNodePtr & node,const std::shared_ptr<SubGraphIRInfo> & gsub)325 void DumpKernelInfo(const CNodePtr &node, const std::shared_ptr<SubGraphIRInfo> &gsub) {
326   if (node == nullptr || gsub == nullptr) {
327     return;
328   }
329   auto kernel_info = node->kernel_info();
330   if (kernel_info == nullptr || !kernel_info->has_build_info()) {
331     return;
332   }
333   gsub->dumpbuf << "      : (";
334   gsub->dumpbuf << PrintOutputTypeShapeFormat(node);
335   gsub->dumpbuf << ")";
336   gsub->dumpbuf << std::endl;
337 }
338 
DumpCNode(const CNodePtr & nd,const FuncGraphPtr & sub_graph,OrderedMap<AnfNodePtr,int32_t> * const para_map,const std::shared_ptr<SubGraphIRInfo> & gsub,bool dump_full_name=false)339 void DumpCNode(const CNodePtr &nd, const FuncGraphPtr &sub_graph, OrderedMap<AnfNodePtr, int32_t> *const para_map,
340                const std::shared_ptr<SubGraphIRInfo> &gsub, bool dump_full_name = false) {
341   if (nd == nullptr || sub_graph == nullptr || para_map == nullptr || gsub == nullptr) {
342     return;
343   }
344 
345   if (nd != sub_graph->get_return()) {
346     gsub->dumpbuf << "  %" << gsub->local_var << "(" << nd->ToString() << ")"
347                   << " = ";
348     gsub->local_var_map[nd] = gsub->local_var++;
349   } else {
350     gsub->dumpbuf << "  ";
351   }
352 
353   if (nd->inputs().empty()) {
354     MS_LOG(EXCEPTION) << "Input of apply node is empty";
355   }
356   AnfNodePtr op = nd->input(0);
357   DumpOperator(op, gsub);
358   DumpOperands(nd, para_map, gsub);
359   DumpOperateAttrs(op, gsub);
360   DumpCNodeAttrs(nd, gsub);
361   DumpCNodePrimalAttrs(nd, gsub);
362   DumpShape(nd, sub_graph, gsub);
363   DumpKernelInfo(nd, gsub);
364   if (dump_full_name) {
365     gsub->dumpbuf << "      : (" << nd->fullname_with_scope() << ")" << std::endl;
366   }
367 }
368 
DumpIRInSubgraph(const std::vector<AnfNodePtr> & nodes,OrderedMap<AnfNodePtr,int32_t> * para_map,OrderedMap<FuncGraphPtr,std::shared_ptr<SubGraphIRInfo>> * const sub_graphs,int32_t total_para,bool dump_full_name=false)369 void DumpIRInSubgraph(const std::vector<AnfNodePtr> &nodes, OrderedMap<AnfNodePtr, int32_t> *para_map,
370                       OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> *const sub_graphs, int32_t total_para,
371                       bool dump_full_name = false) {
372   if (para_map == nullptr || sub_graphs == nullptr) {
373     return;
374   }
375 
376   for (const auto &nd : nodes) {
377     MS_EXCEPTION_IF_NULL(nd);
378     FuncGraphPtr sub_graph = nd->func_graph();
379     if (sub_graph == nullptr) {
380       MS_LOG(DEBUG) << "Node[" << nd->ToString() << "] belongs to no graph!";
381       continue;
382     }
383     std::shared_ptr<SubGraphIRInfo> gsub = (*sub_graphs)[sub_graph];
384     if (gsub == nullptr) {
385       gsub = std::make_shared<SubGraphIRInfo>();
386       gsub->local_var = 0;
387       (*sub_graphs)[sub_graph] = gsub;
388     }
389     auto &param = sub_graph->parameters();
390     for (size_t idx = 0; idx < param.size(); idx++) {
391       MS_EXCEPTION_IF_NULL(param[idx]);
392       if ((*para_map).count(param[idx]) == 0) {
393         (*para_map)[param[idx]] = total_para++;
394       }
395     }
396     if (!nd->isa<Parameter>()) {
397       if (nd->isa<CNode>()) {
398         // print and record output of operator if it is not 'Return'
399         DumpCNode(nd->cast<CNodePtr>(), sub_graph, para_map, gsub, dump_full_name);
400       } else {
401         gsub->dumpbuf << "  " << nd->ToString() << std::endl;
402       }
403     }
404   }
405 }
406 
DumpSubgraph(const OrderedMap<FuncGraphPtr,std::shared_ptr<SubGraphIRInfo>> * sub_graphs,const FuncGraphPtr & graph,OrderedMap<AnfNodePtr,int32_t> * para_map,std::ofstream & fout)407 void DumpSubgraph(const OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> *sub_graphs,
408                   const FuncGraphPtr &graph, OrderedMap<AnfNodePtr, int32_t> *para_map, std::ofstream &fout) {
409   if (sub_graphs == nullptr || graph == nullptr) {
410     return;
411   }
412 
413   fout << "#Total subgraph : " << sub_graphs->size() << std::endl;
414   fout << std::endl;
415 
416   for (const auto &sg : *sub_graphs) {
417     fout << "subgraph attr:" << std::endl;
418     MS_EXCEPTION_IF_NULL(sg.first);
419     for (const auto &attr : sg.first->attrs()) {
420       fout << attr.first << " : ";
421       if (attr.second->isa<BoolImm>()) {
422         fout << GetValue<bool>(attr.second);
423       } else if (attr.second->isa<StringImm>()) {
424         fout << (GetValue<std::string>(attr.second));
425       }
426       fout << std::endl;
427     }
428     fout << "subgraph @" << sg.first->ToString() << "(";
429     if (sg.first != graph) {
430       std::vector<AnfNodePtr> parameters = sg.first->parameters();
431       if (parameters.size() == 1) {
432         MS_EXCEPTION_IF_NULL(parameters[0]);
433         fout << "%para" << (*para_map)[parameters[0]] << "_" << parameters[0]->ToString();
434       } else if (parameters.size() > 1) {
435         for (size_t idx = 0; idx < parameters.size() - 1; idx++) {
436           MS_EXCEPTION_IF_NULL(parameters[idx]);
437           fout << "%para" << (*para_map)[parameters[idx]] << "_" << parameters[idx]->ToString();
438           fout << ", ";
439         }
440         MS_EXCEPTION_IF_NULL(parameters[parameters.size() - 1]);
441         fout << "%para" << (*para_map)[parameters[parameters.size() - 1]] << "_"
442              << parameters[parameters.size() - 1]->ToString();
443       }
444     }
445     fout << ") {" << std::endl;
446     MS_EXCEPTION_IF_NULL(sg.second);
447     fout << sg.second->dumpbuf.str();
448     fout << "}" << std::endl;
449     fout << std::endl;
450   }
451 }
452 
CreatePrefixPath(const std::string & input_path)453 std::optional<std::string> CreatePrefixPath(const std::string &input_path) {
454   std::optional<std::string> prefix_path;
455   std::optional<std::string> file_name;
456   FileUtils::SplitDirAndFileName(input_path, &prefix_path, &file_name);
457   if (!file_name.has_value()) {
458     MS_LOG(ERROR) << "Cannot get file_name from: " << input_path;
459     return std::nullopt;
460   }
461   auto file_name_str = file_name.value();
462   std::string prefix_path_str;
463   if (prefix_path.has_value()) {
464     auto create_prefix_path = FileUtils::CreateNotExistDirs(prefix_path.value(), true);
465     if (!create_prefix_path.has_value()) {
466       return std::nullopt;
467     }
468     prefix_path_str = create_prefix_path.value();
469   } else {
470     auto pwd_path = FileUtils::GetRealPath("./");
471     if (!pwd_path.has_value()) {
472       MS_LOG(ERROR) << "Can not get pwd path";
473       return std::nullopt;
474     }
475     prefix_path_str = pwd_path.value();
476   }
477   return std::string(prefix_path_str + "/" + file_name_str);
478 }
479 
DumpIR(const std::string & filename,const FuncGraphPtr & graph,bool dump_full_name)480 void DumpIR(const std::string &filename, const FuncGraphPtr &graph, bool dump_full_name) {
481   if (graph == nullptr) {
482     return;
483   }
484   auto path = "./" + filename;
485   auto realpath = CreatePrefixPath(path);
486   if (!realpath.has_value()) {
487     MS_LOG(ERROR) << "Get real path failed, path=" << path;
488     return;
489   }
490 
491   std::ofstream fout(realpath.value());
492   std::ostringstream dumpbuf;
493 
494   auto nodes = TopoSort(graph->get_return(), SuccDeeperSimple, AlwaysInclude);
495   OrderedMap<AnfNodePtr, int32_t> para_map;
496   // dump global info
497   DumpGlobalInfoEntry(graph, dumpbuf);
498   int32_t total_para = DumpParams(graph, dumpbuf, &para_map);
499 
500   OrderedMap<FuncGraphPtr, std::shared_ptr<SubGraphIRInfo>> sub_graphs;
501   // dump ir in each sub graph
502   DumpIRInSubgraph(nodes, &para_map, &sub_graphs, total_para, dump_full_name);
503 
504   // output global info
505   fout << dumpbuf.str() << std::endl;
506 
507   // output each sub graph
508   DumpSubgraph(&sub_graphs, graph, &para_map, fout);
509 
510   fout.close();
511 }
512 }  // namespace dumpir
513 
DumpPassIR(const FuncGraphPtr & func_graph,const std::string & pass_fullname) const514 void GraphKernelPassManagerLite::DumpPassIR(const FuncGraphPtr &func_graph, const std::string &pass_fullname) const {
515   static bool dump_ir = (common::GetEnv("MS_DEV_DUMP_GRAPH_KERNEL_IR") == "on");
516   if (dump_ir) {
517     static std::string rank_id = common::GetEnv("RANK_ID");
518     std::string filename;
519     if (rank_id.empty()) {
520       filename = "verbose_ir_files/" + pass_fullname + ".ir";
521     } else {
522       filename = "rank_" + rank_id + "/verbose_ir_files/" + pass_fullname + ".ir";
523     }
524     dumpir::DumpIR(filename, func_graph, true);
525   }
526 }
527 
528 // transplant this function from pass_manager_extends.cc because the implement was moved to PassManagerLite.
RunPass(const FuncGraphPtr & func_graph,size_t pass_id,const PassPtr & pass) const529 bool GraphKernelPassManagerLite::RunPass(const FuncGraphPtr &func_graph, size_t pass_id, const PassPtr &pass) const {
530   bool changed = false;
531   auto begin_time = lite::GetTimeUs();
532   if (pass->Run(func_graph)) {
533     changed = true;
534   }
535   auto end_time = lite::GetTimeUs();
536   MS_LOG(INFO) << "Run pass " << GetPassFullname(pass_id, pass) << " in " << (end_time - begin_time) << " us.";
537   return changed;
538 }
539 }  // namespace mindspore::graphkernel
540